|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Copyright 2002-2025 the original author or authors.
|
|
|
|
|
|
+ * Copyright 2002-2023 the original author or authors.
|
|
*
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* you may not use this file except in compliance with the License.
|
|
@@ -43,7 +43,9 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
|
import org.springframework.security.web.SecurityFilterChain;
|
|
import org.springframework.security.web.SecurityFilterChain;
|
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
|
|
|
+import org.springframework.security.web.authentication.preauth.x509.SubjectX500PrincipalExtractor;
|
|
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
|
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
|
|
|
+import org.springframework.security.web.authentication.preauth.x509.X509TestUtils;
|
|
import org.springframework.test.web.servlet.MockMvc;
|
|
import org.springframework.test.web.servlet.MockMvc;
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
@@ -123,16 +125,6 @@ public class X509ConfigurerTests {
|
|
// @formatter:on
|
|
// @formatter:on
|
|
}
|
|
}
|
|
|
|
|
|
- @Test
|
|
|
|
- public void x509WhenExtractPrincipalNameFromEmailIsTrueThenUsesEmailAddressToExtractPrincipal() throws Exception {
|
|
|
|
- this.spring.register(EmailPrincipalConfig.class).autowire();
|
|
|
|
- X509Certificate certificate = loadCert("max.cer");
|
|
|
|
- // @formatter:off
|
|
|
|
- this.mvc.perform(get("/").with(x509(certificate)))
|
|
|
|
- .andExpect(authenticated().withUsername("maxbatischev@gmail.com"));
|
|
|
|
- // @formatter:on
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
@Test
|
|
@Test
|
|
public void x509WhenUserDetailsServiceNotConfiguredThenUsesBean() throws Exception {
|
|
public void x509WhenUserDetailsServiceNotConfiguredThenUsesBean() throws Exception {
|
|
this.spring.register(UserDetailsServiceBeanConfig.class).autowire();
|
|
this.spring.register(UserDetailsServiceBeanConfig.class).autowire();
|
|
@@ -165,6 +157,28 @@ public class X509ConfigurerTests {
|
|
// @formatter:on
|
|
// @formatter:on
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void x509WhenSubjectX500PrincipalExtractor() throws Exception {
|
|
|
|
+ this.spring.register(SubjectX500PrincipalExtractorConfig.class).autowire();
|
|
|
|
+ X509Certificate certificate = loadCert("rod.cer");
|
|
|
|
+ // @formatter:off
|
|
|
|
+ this.mvc.perform(get("/").with(x509(certificate)))
|
|
|
|
+ .andExpect((result) -> assertThat(result.getRequest().getSession(false)).isNull())
|
|
|
|
+ .andExpect(authenticated().withUsername("rod"));
|
|
|
|
+ // @formatter:on
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Test
|
|
|
|
+ public void x509WhenSubjectX500PrincipalExtractorBean() throws Exception {
|
|
|
|
+ this.spring.register(SubjectX500PrincipalExtractorEmailConfig.class).autowire();
|
|
|
|
+ X509Certificate certificate = X509TestUtils.buildTestCertificate();
|
|
|
|
+ // @formatter:off
|
|
|
|
+ this.mvc.perform(get("/").with(x509(certificate)))
|
|
|
|
+ .andExpect((result) -> assertThat(result.getRequest().getSession(false)).isNull())
|
|
|
|
+ .andExpect(authenticated().withUsername("luke@monkeymachine"));
|
|
|
|
+ // @formatter:on
|
|
|
|
+ }
|
|
|
|
+
|
|
private <T extends Certificate> T loadCert(String location) {
|
|
private <T extends Certificate> T loadCert(String location) {
|
|
try (InputStream is = new ClassPathResource(location).getInputStream()) {
|
|
try (InputStream is = new ClassPathResource(location).getInputStream()) {
|
|
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
|
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
|
@@ -287,33 +301,6 @@ public class X509ConfigurerTests {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- @Configuration
|
|
|
|
- @EnableWebSecurity
|
|
|
|
- static class EmailPrincipalConfig {
|
|
|
|
-
|
|
|
|
- @Bean
|
|
|
|
- SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
|
|
- // @formatter:off
|
|
|
|
- http
|
|
|
|
- .x509((x509) ->
|
|
|
|
- x509.extractPrincipalNameFromEmail(true)
|
|
|
|
- );
|
|
|
|
- // @formatter:on
|
|
|
|
- return http.build();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Bean
|
|
|
|
- UserDetailsService userDetailsService() {
|
|
|
|
- UserDetails user = User.withDefaultPasswordEncoder()
|
|
|
|
- .username("maxbatischev@gmail.com")
|
|
|
|
- .password("password")
|
|
|
|
- .roles("USER", "ADMIN")
|
|
|
|
- .build();
|
|
|
|
- return new InMemoryUserDetailsManager(user);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
@Configuration
|
|
@Configuration
|
|
@EnableWebSecurity
|
|
@EnableWebSecurity
|
|
static class UserDetailsServiceBeanConfig {
|
|
static class UserDetailsServiceBeanConfig {
|
|
@@ -397,4 +384,60 @@ public class X509ConfigurerTests {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Configuration
|
|
|
|
+ @EnableWebSecurity
|
|
|
|
+ static class SubjectX500PrincipalExtractorConfig {
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
|
|
+ // @formatter:off
|
|
|
|
+ http
|
|
|
|
+ .x509((x509) -> x509
|
|
|
|
+ .x509PrincipalExtractor(new SubjectX500PrincipalExtractor())
|
|
|
|
+ );
|
|
|
|
+ // @formatter:on
|
|
|
|
+ return http.build();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ UserDetailsService userDetailsService() {
|
|
|
|
+ UserDetails user = User.withDefaultPasswordEncoder()
|
|
|
|
+ .username("rod")
|
|
|
|
+ .password("password")
|
|
|
|
+ .roles("USER", "ADMIN")
|
|
|
|
+ .build();
|
|
|
|
+ return new InMemoryUserDetailsManager(user);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Configuration
|
|
|
|
+ @EnableWebSecurity
|
|
|
|
+ static class SubjectX500PrincipalExtractorEmailConfig {
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
|
|
+ SubjectX500PrincipalExtractor principalExtractor = new SubjectX500PrincipalExtractor();
|
|
|
|
+ principalExtractor.setExtractPrincipalNameFromEmail(true);
|
|
|
|
+ // @formatter:off
|
|
|
|
+ http
|
|
|
|
+ .x509((x509) -> x509
|
|
|
|
+ .x509PrincipalExtractor(principalExtractor)
|
|
|
|
+ );
|
|
|
|
+ // @formatter:on
|
|
|
|
+ return http.build();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ UserDetailsService userDetailsService() {
|
|
|
|
+ UserDetails user = User.withDefaultPasswordEncoder()
|
|
|
|
+ .username("luke@monkeymachine")
|
|
|
|
+ .password("password")
|
|
|
|
+ .roles("USER", "ADMIN")
|
|
|
|
+ .build();
|
|
|
|
+ return new InMemoryUserDetailsManager(user);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|