Parcourir la source

Allow configuration of security context through nested builder

Issue: gh-5557
Eleftheria Stein il y a 6 ans
Parent
commit
04e0dcfe61

+ 34 - 0
config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java

@@ -62,6 +62,7 @@ import org.springframework.security.web.PortMapper;
 import org.springframework.security.web.PortMapperImpl;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
+import org.springframework.security.web.context.SecurityContextRepository;
 import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
 import org.springframework.security.web.session.HttpSessionEventPublisher;
 import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -1248,6 +1249,39 @@ public final class HttpSecurity extends
 		return getOrApply(new SecurityContextConfigurer<>());
 	}
 
+	/**
+	 * Sets up management of the {@link SecurityContext} on the
+	 * {@link SecurityContextHolder} between {@link HttpServletRequest}'s. This is
+	 * automatically applied when using {@link WebSecurityConfigurerAdapter}.
+	 *
+	 * The following customization specifies the shared {@link SecurityContextRepository}
+	 *
+	 * <pre>
+	 * &#064;Configuration
+	 * &#064;EnableWebSecurity
+	 * public class SecurityContextSecurityConfig extends WebSecurityConfigurerAdapter {
+	 *
+	 * 	&#064;Override
+	 * 	protected void configure(HttpSecurity http) throws Exception {
+	 * 		http
+	 * 			.securityContext(securityContext ->
+	 * 				securityContext
+	 * 					.securityContextRepository(SCR)
+	 * 			);
+	 * 	}
+	 * }
+	 * </pre>
+	 *
+	 * @param securityContextCustomizer the {@link Customizer} to provide more options for
+	 * the {@link SecurityContextConfigurer}
+	 * @return the {@link HttpSecurity} for further customizations
+	 * @throws Exception
+	 */
+	public HttpSecurity securityContext(Customizer<SecurityContextConfigurer<HttpSecurity>> securityContextCustomizer) throws Exception {
+		securityContextCustomizer.customize(getOrApply(new SecurityContextConfigurer<>()));
+		return HttpSecurity.this;
+	}
+
 	/**
 	 * Integrates the {@link HttpServletRequest} methods with the values found on the
 	 * {@link SecurityContext}. This is automatically applied when using

+ 101 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java

@@ -28,14 +28,22 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.test.SpringTestRule;
 import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.userdetails.PasswordEncodedUser;
 import org.springframework.security.web.context.HttpRequestResponseHolder;
+import org.springframework.security.web.context.NullSecurityContextRepository;
 import org.springframework.security.web.context.SecurityContextPersistenceFilter;
 import org.springframework.security.web.context.SecurityContextRepository;
 import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
 import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
 
+import javax.servlet.http.HttpSession;
+
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.*;
+import static org.springframework.security.config.Customizer.withDefaults;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 
 /**
@@ -151,4 +159,97 @@ public class SecurityContextConfigurerTests {
 			// @formatter:on
 		}
 	}
+
+	@Test
+	public void requestWhenSecurityContextWithDefaultsInLambdaThenSessionIsCreated() throws Exception {
+		this.spring.register(SecurityContextWithDefaultsInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+		assertThat(session).isNotNull();
+	}
+
+	@EnableWebSecurity
+	static class SecurityContextWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin(withDefaults())
+				.securityContext(withDefaults());
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
+
+	@Test
+	public void requestWhenSecurityContextDisabledInLambdaThenContextNotSavedInSession() throws Exception {
+		this.spring.register(SecurityContextDisabledInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+		assertThat(session).isNull();
+	}
+
+	@EnableWebSecurity
+	static class SecurityContextDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin(withDefaults())
+				.securityContext(AbstractHttpConfigurer::disable);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
+
+	@Test
+	public void requestWhenNullSecurityContextRepositoryInLambdaThenContextNotSavedInSession() throws Exception {
+		this.spring.register(NullSecurityContextRepositoryInLambdaConfig.class).autowire();
+
+		MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+		HttpSession session = mvcResult.getRequest().getSession(false);
+		assertThat(session).isNull();
+	}
+
+	@EnableWebSecurity
+	static class NullSecurityContextRepositoryInLambdaConfig extends WebSecurityConfigurerAdapter {
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+			// @formatter:off
+			http
+				.formLogin(withDefaults())
+				.securityContext(securityContext ->
+					securityContext
+						.securityContextRepository(new NullSecurityContextRepository())
+				);
+			// @formatter:on
+		}
+
+		@Override
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			// @formatter:off
+			auth
+				.inMemoryAuthentication()
+					.withUser(PasswordEncodedUser.user());
+			// @formatter:on
+		}
+	}
 }