|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2019 the original author or authors. |
| 2 | + * Copyright 2002-2022 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
34 | 34 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
35 | 35 | import org.springframework.security.config.test.SpringTestContext;
|
36 | 36 | import org.springframework.security.config.test.SpringTestContextExtension;
|
| 37 | +import org.springframework.security.core.userdetails.User; |
| 38 | +import org.springframework.security.core.userdetails.UserDetailsService; |
| 39 | +import org.springframework.security.provisioning.InMemoryUserDetailsManager; |
| 40 | +import org.springframework.security.web.SecurityFilterChain; |
37 | 41 | import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
38 | 42 | import org.springframework.test.web.servlet.MockMvc;
|
39 | 43 |
|
40 | 44 | import static org.mockito.ArgumentMatchers.any;
|
| 45 | +import static org.mockito.Mockito.mock; |
41 | 46 | import static org.mockito.Mockito.spy;
|
42 | 47 | import static org.mockito.Mockito.verify;
|
43 | 48 | import static org.springframework.security.config.Customizer.withDefaults;
|
@@ -95,6 +100,26 @@ public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal
|
95 | 100 | // @formatter:on
|
96 | 101 | }
|
97 | 102 |
|
| 103 | + @Test |
| 104 | + public void x509WhenUserDetailsServiceNotConfiguredThenUsesBean() throws Exception { |
| 105 | + this.spring.register(UserDetailsServiceBeanConfig.class).autowire(); |
| 106 | + X509Certificate certificate = loadCert("rod.cer"); |
| 107 | + // @formatter:off |
| 108 | + this.mvc.perform(get("/").with(x509(certificate))) |
| 109 | + .andExpect(authenticated().withUsername("rod")); |
| 110 | + // @formatter:on |
| 111 | + } |
| 112 | + |
| 113 | + @Test |
| 114 | + public void x509WhenUserDetailsServiceAndBeanConfiguredThenDoesNotUseBean() throws Exception { |
| 115 | + this.spring.register(UserDetailsServiceAndBeanConfig.class).autowire(); |
| 116 | + X509Certificate certificate = loadCert("rod.cer"); |
| 117 | + // @formatter:off |
| 118 | + this.mvc.perform(get("/").with(x509(certificate))) |
| 119 | + .andExpect(authenticated().withUsername("rod")); |
| 120 | + // @formatter:on |
| 121 | + } |
| 122 | + |
98 | 123 | private <T extends Certificate> T loadCert(String location) {
|
99 | 124 | try (InputStream is = new ClassPathResource(location).getInputStream()) {
|
100 | 125 | CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
@@ -206,4 +231,59 @@ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
206 | 231 |
|
207 | 232 | }
|
208 | 233 |
|
| 234 | + @EnableWebSecurity |
| 235 | + static class UserDetailsServiceBeanConfig { |
| 236 | + |
| 237 | + @Bean |
| 238 | + SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { |
| 239 | + // @formatter:off |
| 240 | + http |
| 241 | + .x509(withDefaults()); |
| 242 | + // @formatter:on |
| 243 | + return http.build(); |
| 244 | + } |
| 245 | + |
| 246 | + @Bean |
| 247 | + UserDetailsService userDetailsService() { |
| 248 | + // @formatter:off |
| 249 | + return new InMemoryUserDetailsManager( |
| 250 | + User.withDefaultPasswordEncoder() |
| 251 | + .username("rod") |
| 252 | + .password("password") |
| 253 | + .roles("USER", "ADMIN") |
| 254 | + .build() |
| 255 | + ); |
| 256 | + // @formatter:on |
| 257 | + } |
| 258 | + |
| 259 | + } |
| 260 | + |
| 261 | + @EnableWebSecurity |
| 262 | + static class UserDetailsServiceAndBeanConfig { |
| 263 | + |
| 264 | + @Bean |
| 265 | + SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { |
| 266 | + // @formatter:off |
| 267 | + UserDetailsService customUserDetailsService = new InMemoryUserDetailsManager( |
| 268 | + User.withDefaultPasswordEncoder() |
| 269 | + .username("rod") |
| 270 | + .password("password") |
| 271 | + .roles("USER", "ADMIN") |
| 272 | + .build()); |
| 273 | + http |
| 274 | + .x509((x509) -> x509 |
| 275 | + .userDetailsService(customUserDetailsService) |
| 276 | + ); |
| 277 | + // @formatter:on |
| 278 | + return http.build(); |
| 279 | + } |
| 280 | + |
| 281 | + @Bean |
| 282 | + UserDetailsService userDetailsService() { |
| 283 | + // @formatter:off |
| 284 | + return mock(UserDetailsService.class); |
| 285 | + } |
| 286 | + |
| 287 | + } |
| 288 | + |
209 | 289 | }
|
0 commit comments