Răsfoiți Sursa

Defer Anonymous Filter Construction

By delaying when the AnonymousAuthenticationFilter is constructed,
it's now possible to call the principal and filter methods inside
of a custom DSL implementation.

This does not extend to setting the key or the authentication provider
though, as these must be set during the init phase.

Closes gh-14941
Josh Cummings 1 an în urmă
părinte
comite
664dfd9b45

+ 15 - 8
config/src/main/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurer.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -53,6 +53,8 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
 
 	private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS");
 
+	private String computedKey;
+
 	/**
 	 * Creates a new instance
 	 * @see HttpSecurity#anonymous()
@@ -144,26 +146,31 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
 		if (this.authenticationProvider == null) {
 			this.authenticationProvider = new AnonymousAuthenticationProvider(getKey());
 		}
-		if (this.authenticationFilter == null) {
-			this.authenticationFilter = new AnonymousAuthenticationFilter(getKey(), this.principal, this.authorities);
-			this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
-		}
-		this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
 		this.authenticationProvider = postProcess(this.authenticationProvider);
 		http.authenticationProvider(this.authenticationProvider);
 	}
 
 	@Override
 	public void configure(H http) {
+		if (this.authenticationFilter == null) {
+			this.authenticationFilter = new AnonymousAuthenticationFilter(getKey(), this.principal, this.authorities);
+		}
+		this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
 		this.authenticationFilter.afterPropertiesSet();
 		http.addFilter(this.authenticationFilter);
 	}
 
 	private String getKey() {
+		if (this.computedKey != null) {
+			return this.computedKey;
+		}
 		if (this.key == null) {
-			this.key = UUID.randomUUID().toString();
+			this.computedKey = UUID.randomUUID().toString();
+		}
+		else {
+			this.computedKey = this.key;
 		}
-		return this.key;
+		return this.computedKey;
 	}
 
 }

+ 34 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -94,6 +94,13 @@ public class AnonymousConfigurerTests {
 		this.mockMvc.perform(get("/")).andExpect(status().isOk());
 	}
 
+	// gh-14941
+	@Test
+	public void shouldReturnMyCustomAnonymousConfig() throws Exception {
+		this.spring.register(AnonymousInCustomConfigurer.class, PrincipalController.class).autowire();
+		this.mockMvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("myAnonymousUser"));
+	}
+
 	@Configuration
 	@EnableWebSecurity
 	@EnableWebMvc
@@ -181,6 +188,32 @@ public class AnonymousConfigurerTests {
 
 	}
 
+	@Configuration
+	@EnableWebMvc
+	@EnableWebSecurity
+	static class AnonymousInCustomConfigurer {
+
+		@Bean
+		SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
+				.with(new CustomDsl(), withDefaults());
+			// @formatter:on
+			return http.build();
+		}
+
+		static class CustomDsl extends AbstractHttpConfigurer<CustomDsl, HttpSecurity> {
+
+			@Override
+			public void init(HttpSecurity http) throws Exception {
+				http.anonymous((anonymous) -> anonymous.principal("myAnonymousUser"));
+			}
+
+		}
+
+	}
+
 	@RestController
 	static class PrincipalController {