diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index 7c1acd7200..7d8654687d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -751,6 +751,86 @@ public final class HttpSecurity extends return getOrApply(new JeeConfigurer<>()); } + /** + * Configures container based pre authentication. In this case, authentication + * is managed by the Servlet Container. + * + *

Example Configuration

+ * + * The following configuration will use the principal found on the + * {@link HttpServletRequest} and if the user is in the role "ROLE_USER" or + * "ROLE_ADMIN" will add that to the resulting {@link Authentication}. + * + *
+	 * @Configuration
+	 * @EnableWebSecurity
+	 * public class JeeSecurityConfig extends WebSecurityConfigurerAdapter {
+	 *
+	 * 	@Override
+	 * 	protected void configure(HttpSecurity http) throws Exception {
+	 * 		http
+	 * 			.authorizeRequests()
+	 * 				.antMatchers("/**").hasRole("USER")
+	 * 				.and()
+	 * 			.jee(jee ->
+	 * 				jee
+	 * 					.mappableRoles("USER", "ADMIN")
+	 * 			);
+	 * 	}
+	 * }
+	 * 
+ * + * Developers wishing to use pre authentication with the container will need to ensure + * their web.xml configures the security constraints. For example, the web.xml (there + * is no equivalent Java based configuration supported by the Servlet specification) + * might look like: + * + *
+	 * <login-config>
+	 *     <auth-method>FORM</auth-method>
+	 *     <form-login-config>
+	 *         <form-login-page>/login</form-login-page>
+	 *         <form-error-page>/login?error</form-error-page>
+	 *     </form-login-config>
+	 * </login-config>
+	 *
+	 * <security-role>
+	 *     <role-name>ROLE_USER</role-name>
+	 * </security-role>
+	 * <security-constraint>
+	 *     <web-resource-collection>
+	 *     <web-resource-name>Public</web-resource-name>
+	 *         <description>Matches unconstrained pages</description>
+	 *         <url-pattern>/login</url-pattern>
+	 *         <url-pattern>/logout</url-pattern>
+	 *         <url-pattern>/resources/*</url-pattern>
+	 *     </web-resource-collection>
+	 * </security-constraint>
+	 * <security-constraint>
+	 *     <web-resource-collection>
+	 *         <web-resource-name>Secured Areas</web-resource-name>
+	 *         <url-pattern>/*</url-pattern>
+	 *     </web-resource-collection>
+	 *     <auth-constraint>
+	 *         <role-name>ROLE_USER</role-name>
+	 *     </auth-constraint>
+	 * </security-constraint>
+	 * 
+ * + * Last you will need to configure your container to contain the user with the correct + * roles. This configuration is specific to the Servlet Container, so consult your + * Servlet Container's documentation. + * + * @param jeeCustomizer the {@link Customizer} to provide more options for + * the {@link JeeConfigurer} + * @return the {@link HttpSecurity} for further customizations + * @throws Exception + */ + public HttpSecurity jee(Customizer> jeeCustomizer) throws Exception { + jeeCustomizer.customize(getOrApply(new JeeConfigurer<>())); + return HttpSecurity.this; + } + /** * Configures X509 based pre authentication. * diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java index fac4baf354..c55ad59f47 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java @@ -25,6 +25,9 @@ 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.WebSecurityConfigurerAdapter; import org.springframework.security.config.test.SpringTestRule; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; +import org.springframework.security.core.userdetails.User; import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource; import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter; import org.springframework.test.web.servlet.MockMvc; @@ -125,4 +128,112 @@ public class JeeConfigurerTests { // @formatter:on } } + + @Test + public void requestWhenJeeMappableRolesInLambdaThenAuthenticatedWithMappableRoles() throws Exception { + this.spring.register(JeeMappableRolesConfig.class).autowire(); + Principal user = mock(Principal.class); + when(user.getName()).thenReturn("user"); + + this.mvc.perform(get("/") + .principal(user) + .with(request -> { + request.addUserRole("ROLE_ADMIN"); + request.addUserRole("ROLE_USER"); + return request; + })) + .andExpect(authenticated().withRoles("USER")); + } + + @EnableWebSecurity + public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .jee(jee -> + jee + .mappableRoles("USER") + ); + // @formatter:on + } + } + + @Test + public void requestWhenJeeMappableAuthoritiesInLambdaThenAuthenticatedWithMappableAuthorities() throws Exception { + this.spring.register(JeeMappableAuthoritiesConfig.class).autowire(); + Principal user = mock(Principal.class); + when(user.getName()).thenReturn("user"); + + this.mvc.perform(get("/") + .principal(user) + .with(request -> { + request.addUserRole("ROLE_ADMIN"); + request.addUserRole("ROLE_USER"); + return request; + })) + .andExpect(authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER"))); + } + + @EnableWebSecurity + public static class JeeMappableAuthoritiesConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .jee(jee -> + jee + .mappableAuthorities("ROLE_USER") + ); + // @formatter:on + } + } + + @Test + public void requestWhenCustomAuthenticatedUserDetailsServiceInLambdaThenCustomAuthenticatedUserDetailsServiceUsed() + throws Exception { + this.spring.register(JeeCustomAuthenticatedUserDetailsServiceConfig.class).autowire(); + Principal user = mock(Principal.class); + User userDetails = new User("user", "N/A", true, true, true, true, + AuthorityUtils.createAuthorityList("ROLE_USER")); + when(user.getName()).thenReturn("user"); + when(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any())) + .thenReturn(userDetails); + + this.mvc.perform(get("/") + .principal(user) + .with(request -> { + request.addUserRole("ROLE_ADMIN"); + request.addUserRole("ROLE_USER"); + return request; + })) + .andExpect(authenticated().withRoles("USER")); + } + + @EnableWebSecurity + public static class JeeCustomAuthenticatedUserDetailsServiceConfig extends WebSecurityConfigurerAdapter { + static AuthenticationUserDetailsService authenticationUserDetailsService = + mock(AuthenticationUserDetailsService.class); + + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .authorizeRequests() + .anyRequest().hasRole("USER") + .and() + .jee(jee -> + jee + .authenticatedUserDetailsService(authenticationUserDetailsService) + ); + // @formatter:on + } + } }