Ability to configure authenticationDetailsSource in AnonymousConfigurer
Closes gh-17831 Signed-off-by: DingHao <dh.hiekn@gmail.com>
This commit is contained in:
		
							parent
							
								
									10935632ee
								
							
						
					
					
						commit
						57d9678b4b
					
				|  | @ -19,7 +19,10 @@ package org.springframework.security.config.annotation.web.configurers; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| 
 | 
 | ||||||
|  | import jakarta.servlet.http.HttpServletRequest; | ||||||
|  | 
 | ||||||
| import org.springframework.security.authentication.AnonymousAuthenticationProvider; | import org.springframework.security.authentication.AnonymousAuthenticationProvider; | ||||||
|  | import org.springframework.security.authentication.AuthenticationDetailsSource; | ||||||
| import org.springframework.security.authentication.AuthenticationProvider; | import org.springframework.security.authentication.AuthenticationProvider; | ||||||
| import org.springframework.security.config.Customizer; | import org.springframework.security.config.Customizer; | ||||||
| import org.springframework.security.config.annotation.SecurityConfigurer; | import org.springframework.security.config.annotation.SecurityConfigurer; | ||||||
|  | @ -39,6 +42,7 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi | ||||||
|  * other than applying this {@link SecurityConfigurer}. |  * other than applying this {@link SecurityConfigurer}. | ||||||
|  * |  * | ||||||
|  * @author Rob Winch |  * @author Rob Winch | ||||||
|  |  * @author DingHao | ||||||
|  * @since 3.2 |  * @since 3.2 | ||||||
|  */ |  */ | ||||||
| public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> | public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> | ||||||
|  | @ -50,6 +54,8 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> | ||||||
| 
 | 
 | ||||||
| 	private AnonymousAuthenticationFilter authenticationFilter; | 	private AnonymousAuthenticationFilter authenticationFilter; | ||||||
| 
 | 
 | ||||||
|  | 	private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource; | ||||||
|  | 
 | ||||||
| 	private Object principal = "anonymousUser"; | 	private Object principal = "anonymousUser"; | ||||||
| 
 | 
 | ||||||
| 	private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"); | 	private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"); | ||||||
|  | @ -142,6 +148,19 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> | ||||||
| 		return this; | 		return this; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Specifies a custom {@link AuthenticationDetailsSource} to use for anonymous | ||||||
|  | 	 * authentication. | ||||||
|  | 	 * @param authenticationDetailsSource the custom {@link AuthenticationDetailsSource} | ||||||
|  | 	 * to use | ||||||
|  | 	 * @return {@link AnonymousConfigurer} for additional customization | ||||||
|  | 	 */ | ||||||
|  | 	public AnonymousConfigurer<H> authenticationDetailsSource( | ||||||
|  | 			AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) { | ||||||
|  | 		this.authenticationDetailsSource = authenticationDetailsSource; | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void init(H http) { | 	public void init(H http) { | ||||||
| 		if (this.authenticationProvider == null) { | 		if (this.authenticationProvider == null) { | ||||||
|  | @ -156,6 +175,9 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> | ||||||
| 		if (this.authenticationFilter == null) { | 		if (this.authenticationFilter == null) { | ||||||
| 			this.authenticationFilter = new AnonymousAuthenticationFilter(getKey(), this.principal, this.authorities); | 			this.authenticationFilter = new AnonymousAuthenticationFilter(getKey(), this.principal, this.authorities); | ||||||
| 		} | 		} | ||||||
|  | 		if (this.authenticationDetailsSource != null) { | ||||||
|  | 			this.authenticationFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource); | ||||||
|  | 		} | ||||||
| 		this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy()); | 		this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy()); | ||||||
| 		this.authenticationFilter.afterPropertiesSet(); | 		this.authenticationFilter.afterPropertiesSet(); | ||||||
| 		http.addFilter(this.authenticationFilter); | 		http.addFilter(this.authenticationFilter); | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
| 
 | 
 | ||||||
| package org.springframework.security.config.annotation.web.configurers; | package org.springframework.security.config.annotation.web.configurers; | ||||||
| 
 | 
 | ||||||
|  | import jakarta.servlet.http.HttpServletRequest; | ||||||
| import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||||
| import org.junit.jupiter.api.extension.ExtendWith; | import org.junit.jupiter.api.extension.ExtendWith; | ||||||
| 
 | 
 | ||||||
|  | @ -23,6 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
| import org.springframework.security.authentication.AnonymousAuthenticationToken; | import org.springframework.security.authentication.AnonymousAuthenticationToken; | ||||||
|  | import org.springframework.security.authentication.AuthenticationDetailsSource; | ||||||
| import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; | import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig; | ||||||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; | import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||||||
| import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | ||||||
|  | @ -39,6 +41,8 @@ import org.springframework.web.bind.annotation.GetMapping; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| import org.springframework.web.servlet.config.annotation.EnableWebMvc; | import org.springframework.web.servlet.config.annotation.EnableWebMvc; | ||||||
| 
 | 
 | ||||||
|  | import static org.mockito.ArgumentMatchers.any; | ||||||
|  | import static org.mockito.Mockito.mock; | ||||||
| import static org.mockito.Mockito.verify; | import static org.mockito.Mockito.verify; | ||||||
| import static org.springframework.security.config.Customizer.withDefaults; | import static org.springframework.security.config.Customizer.withDefaults; | ||||||
| import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication; | import static org.springframework.security.config.annotation.SecurityContextChangedListenerArgumentMatchers.setAuthentication; | ||||||
|  | @ -101,6 +105,37 @@ public class AnonymousConfigurerTests { | ||||||
| 		this.mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("myAnonymousUser")); | 		this.mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("myAnonymousUser")); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void anonymousAuthenticationWhenUsingAuthenticationDetailsSourceRefThenMatchesNamespace() throws Exception { | ||||||
|  | 		this.spring.register(AuthenticationDetailsSourceAnonymousConfig.class).autowire(); | ||||||
|  | 		AuthenticationDetailsSource<HttpServletRequest, ?> source = this.spring.getContext() | ||||||
|  | 			.getBean(AuthenticationDetailsSource.class); | ||||||
|  | 		this.mockMvc.perform(get("/")); | ||||||
|  | 		verify(source).buildDetails(any(HttpServletRequest.class)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Configuration | ||||||
|  | 	@EnableWebSecurity | ||||||
|  | 	@EnableWebMvc | ||||||
|  | 	static class AuthenticationDetailsSourceAnonymousConfig { | ||||||
|  | 
 | ||||||
|  | 		AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = mock( | ||||||
|  | 				AuthenticationDetailsSource.class); | ||||||
|  | 
 | ||||||
|  | 		@Bean | ||||||
|  | 		SecurityFilterChain filterChain(HttpSecurity http) throws Exception { | ||||||
|  | 			return http | ||||||
|  | 				.anonymous((anonymous) -> anonymous.authenticationDetailsSource(this.authenticationDetailsSource)) | ||||||
|  | 				.build(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Bean | ||||||
|  | 		AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource() { | ||||||
|  | 			return this.authenticationDetailsSource; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	@Configuration | 	@Configuration | ||||||
| 	@EnableWebSecurity | 	@EnableWebSecurity | ||||||
| 	@EnableWebMvc | 	@EnableWebMvc | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue