Java tutorial
/* * Copyright 2002-2019 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. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.security.config.annotation.web.builders; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder; import org.springframework.security.config.annotation.ObjectPostProcessor; import org.springframework.security.config.annotation.SecurityBuilder; import org.springframework.security.config.annotation.SecurityConfigurer; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer; import org.springframework.security.config.annotation.web.configurers.ChannelSecurityConfigurer; import org.springframework.security.config.annotation.web.configurers.CorsConfigurer; import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer; import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.config.annotation.web.configurers.HttpBasicConfigurer; import org.springframework.security.config.annotation.web.configurers.JeeConfigurer; import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer; import org.springframework.security.config.annotation.web.configurers.PortMapperConfigurer; import org.springframework.security.config.annotation.web.configurers.RememberMeConfigurer; import org.springframework.security.config.annotation.web.configurers.RequestCacheConfigurer; import org.springframework.security.config.annotation.web.configurers.SecurityContextConfigurer; import org.springframework.security.config.annotation.web.configurers.ServletApiConfigurer; import org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer; import org.springframework.security.config.annotation.web.configurers.X509Configurer; import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2ClientConfigurer; import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer; import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.DefaultSecurityFilterChain; 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; import org.springframework.security.web.util.matcher.AnyRequestMatcher; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RegexRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import javax.servlet.Filter; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; /** * A {@link HttpSecurity} is similar to Spring Security's XML <http> element in the * namespace configuration. It allows configuring web based security for specific http * requests. By default it will be applied to all requests, but can be restricted using * {@link #requestMatcher(RequestMatcher)} or other similar methods. * * <h2>Example Usage</h2> * * The most basic form based configuration can be seen below. The configuration will * require that any URL that is requested will require a User with the role "ROLE_USER". * It also defines an in memory authentication scheme with a user that has the username * "user", the password "password", and the role "ROLE_USER". For additional examples, * refer to the Java Doc of individual methods on {@link HttpSecurity}. * * <pre> * @Configuration * @EnableWebSecurity * public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * @author Rob Winch * @author Joe Grandja * @since 3.2 * @see EnableWebSecurity */ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity> implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> { private final RequestMatcherConfigurer requestMatcherConfigurer; private List<Filter> filters = new ArrayList<>(); private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE; private FilterComparator comparator = new FilterComparator(); /** * Creates a new instance * @param objectPostProcessor the {@link ObjectPostProcessor} that should be used * @param authenticationBuilder the {@link AuthenticationManagerBuilder} to use for * additional updates * @param sharedObjects the shared Objects to initialize the {@link HttpSecurity} with * @see WebSecurityConfiguration */ @SuppressWarnings("unchecked") public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor, AuthenticationManagerBuilder authenticationBuilder, Map<Class<? extends Object>, Object> sharedObjects) { super(objectPostProcessor); Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null"); setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder); for (Map.Entry<Class<? extends Object>, Object> entry : sharedObjects.entrySet()) { setSharedObject((Class<Object>) entry.getKey(), entry.getValue()); } ApplicationContext context = (ApplicationContext) sharedObjects.get(ApplicationContext.class); this.requestMatcherConfigurer = new RequestMatcherConfigurer(context); } private ApplicationContext getContext() { return getSharedObject(ApplicationContext.class); } /** * Allows configuring OpenID based authentication. * * <h2>Example Configurations</h2> * * A basic example accepting the defaults and not using attribute exchange: * * <pre> * @Configuration * @EnableWebSecurity * public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().openidLogin() * .permitAll(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication() * // the username must match the OpenID of the user you are * // logging in with * .withUser( * "https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU") * .password("password").roles("USER"); * } * } * </pre> * * A more advanced example demonstrating using attribute exchange and providing a * custom AuthenticationUserDetailsService that will make any user that authenticates * a valid user. * * <pre> * @Configuration * @EnableWebSecurity * public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) { * http.authorizeRequests() * .antMatchers("/**") * .hasRole("USER") * .and() * .openidLogin() * .loginPage("/login") * .permitAll() * .authenticationUserDetailsService( * new AutoProvisioningUserDetailsService()) * .attributeExchange("https://www.google.com/.*").attribute("email") * .type("https://axschema.org/contact/email").required(true).and() * .attribute("firstname").type("https://axschema.org/namePerson/first") * .required(true).and().attribute("lastname") * .type("https://axschema.org/namePerson/last").required(true).and().and() * .attributeExchange(".*yahoo.com.*").attribute("email") * .type("https://schema.openid.net/contact/email").required(true).and() * .attribute("fullname").type("https://axschema.org/namePerson") * .required(true).and().and().attributeExchange(".*myopenid.com.*") * .attribute("email").type("https://schema.openid.net/contact/email") * .required(true).and().attribute("fullname") * .type("https://schema.openid.net/namePerson").required(true); * } * } * * public class AutoProvisioningUserDetailsService implements * AuthenticationUserDetailsService<OpenIDAuthenticationToken> { * public UserDetails loadUserDetails(OpenIDAuthenticationToken token) * throws UsernameNotFoundException { * return new User(token.getName(), "NOTUSED", * AuthorityUtils.createAuthorityList("ROLE_USER")); * } * } * </pre> * * @return the {@link OpenIDLoginConfigurer} for further customizations. * * @throws Exception * @see OpenIDLoginConfigurer */ public OpenIDLoginConfigurer<HttpSecurity> openidLogin() throws Exception { return getOrApply(new OpenIDLoginConfigurer<>()); } /** * Allows configuring OpenID based authentication. * * <h2>Example Configurations</h2> * * A basic example accepting the defaults and not using attribute exchange: * * <pre> * @Configuration * @EnableWebSecurity * public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .openidLogin(openidLogin -> * openidLogin * .permitAll() * ); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication() * // the username must match the OpenID of the user you are * // logging in with * .withUser( * "https://www.google.com/accounts/o8/id?id=lmkCn9xzPdsxVwG7pjYMuDgNNdASFmobNkcRPaWU") * .password("password").roles("USER"); * } * } * </pre> * * A more advanced example demonstrating using attribute exchange and providing a * custom AuthenticationUserDetailsService that will make any user that authenticates * a valid user. * * <pre> * @Configuration * @EnableWebSecurity * public class OpenIDLoginConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .openidLogin(openidLogin -> * openidLogin * .loginPage("/login") * .permitAll() * .authenticationUserDetailsService( * new AutoProvisioningUserDetailsService()) * .attributeExchange(googleExchange -> * googleExchange * .identifierPattern("https://www.google.com/.*") * .attribute(emailAttribute -> * emailAttribute * .name("email") * .type("https://axschema.org/contact/email") * .required(true) * ) * .attribute(firstnameAttribute -> * firstnameAttribute * .name("firstname") * .type("https://axschema.org/namePerson/first") * .required(true) * ) * .attribute(lastnameAttribute -> * lastnameAttribute * .name("lastname") * .type("https://axschema.org/namePerson/last") * .required(true) * ) * ) * .attributeExchange(yahooExchange -> * yahooExchange * .identifierPattern(".*yahoo.com.*") * .attribute(emailAttribute -> * emailAttribute * .name("email") * .type("https://schema.openid.net/contact/email") * .required(true) * ) * .attribute(fullnameAttribute -> * fullnameAttribute * .name("fullname") * .type("https://axschema.org/namePerson") * .required(true) * ) * ) * ); * } * } * * public class AutoProvisioningUserDetailsService implements * AuthenticationUserDetailsService<OpenIDAuthenticationToken> { * public UserDetails loadUserDetails(OpenIDAuthenticationToken token) * throws UsernameNotFoundException { * return new User(token.getName(), "NOTUSED", * AuthorityUtils.createAuthorityList("ROLE_USER")); * } * } * </pre> * * @see OpenIDLoginConfigurer * * @param openidLoginCustomizer the {@link Customizer} to provide more options for * the {@link OpenIDLoginConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity openidLogin(Customizer<OpenIDLoginConfigurer<HttpSecurity>> openidLoginCustomizer) throws Exception { openidLoginCustomizer.customize(getOrApply(new OpenIDLoginConfigurer<>())); return HttpSecurity.this; } /** * Adds the Security headers to the response. This is activated by default when using * {@link WebSecurityConfigurerAdapter}'s default constructor. Accepting the * default provided by {@link WebSecurityConfigurerAdapter} or only invoking * {@link #headers()} without invoking additional methods on it, is the equivalent of: * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .headers() * .contentTypeOptions() * .and() * .xssProtection() * .and() * .cacheControl() * .and() * .httpStrictTransportSecurity() * .and() * .frameOptions() * .and() * ...; * } * } * </pre> * * You can disable the headers using the following: * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .headers().disable() * ...; * } * } * </pre> * * You can enable only a few of the headers by first invoking * {@link HeadersConfigurer#defaultsDisabled()} * and then invoking the appropriate methods on the {@link #headers()} result. * For example, the following will enable {@link HeadersConfigurer#cacheControl()} and * {@link HeadersConfigurer#frameOptions()} only. * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .headers() * .defaultsDisabled() * .cacheControl() * .and() * .frameOptions() * .and() * ...; * } * } * </pre> * * You can also choose to keep the defaults but explicitly disable a subset of headers. * For example, the following will enable all the default headers except * {@link HeadersConfigurer#frameOptions()}. * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .headers() * .frameOptions() * .disable() * .and() * ...; * } * } * </pre> * * @return the {@link HeadersConfigurer} for further customizations * @throws Exception * @see HeadersConfigurer */ public HeadersConfigurer<HttpSecurity> headers() throws Exception { return getOrApply(new HeadersConfigurer<>()); } /** * Adds the Security headers to the response. This is activated by default when using * {@link WebSecurityConfigurerAdapter}'s default constructor. * * <h2>Example Configurations</h2> * * Accepting the default provided by {@link WebSecurityConfigurerAdapter} or only invoking * {@link #headers()} without invoking additional methods on it, is the equivalent of: * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .headers(headers -> * headers * .contentTypeOptions(withDefaults()) * .xssProtection(withDefaults()) * .cacheControl(withDefaults()) * .httpStrictTransportSecurity(withDefaults()) * .frameOptions(withDefaults() * ); * } * } * </pre> * * You can disable the headers using the following: * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .headers(headers -> headers.disable()); * } * } * </pre> * * You can enable only a few of the headers by first invoking * {@link HeadersConfigurer#defaultsDisabled()} * and then invoking the appropriate methods on the {@link #headers()} result. * For example, the following will enable {@link HeadersConfigurer#cacheControl()} and * {@link HeadersConfigurer#frameOptions()} only. * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .headers(headers -> * headers * .defaultsDisabled() * .cacheControl(withDefaults()) * .frameOptions(withDefaults()) * ); * } * } * </pre> * * You can also choose to keep the defaults but explicitly disable a subset of headers. * For example, the following will enable all the default headers except * {@link HeadersConfigurer#frameOptions()}. * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .headers(headers -> * headers * .frameOptions(frameOptions -> frameOptions.disable()) * ); * } * </pre> * * @param headersCustomizer the {@link Customizer} to provide more options for * the {@link HeadersConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity headers(Customizer<HeadersConfigurer<HttpSecurity>> headersCustomizer) throws Exception { headersCustomizer.customize(getOrApply(new HeadersConfigurer<>())); return HttpSecurity.this; } /** * Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is * provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is * defined, then that {@link CorsConfiguration} is used. Otherwise, if Spring MVC is * on the classpath a {@link HandlerMappingIntrospector} is used. * * @return the {@link CorsConfigurer} for customizations * @throws Exception */ public CorsConfigurer<HttpSecurity> cors() throws Exception { return getOrApply(new CorsConfigurer<>()); } /** * Adds a {@link CorsFilter} to be used. If a bean by the name of corsFilter is * provided, that {@link CorsFilter} is used. Else if corsConfigurationSource is * defined, then that {@link CorsConfiguration} is used. Otherwise, if Spring MVC is * on the classpath a {@link HandlerMappingIntrospector} is used. * You can enable CORS using: * * <pre> * @Configuration * @EnableWebSecurity * public class CorsSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .cors(withDefaults()); * } * } * </pre> * * @param corsCustomizer the {@link Customizer} to provide more options for * the {@link CorsConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity cors(Customizer<CorsConfigurer<HttpSecurity>> corsCustomizer) throws Exception { corsCustomizer.customize(getOrApply(new CorsConfigurer<>())); return HttpSecurity.this; } /** * Allows configuring of Session Management. * * <h2>Example Configuration</h2> * * The following configuration demonstrates how to enforce that only a single instance * of a user is authenticated at a time. If a user authenticates with the username * "user" without logging out and an attempt to authenticate with "user" is made the * first session will be forcibly terminated and sent to the "/login?expired" URL. * * <pre> * @Configuration * @EnableWebSecurity * public class SessionManagementSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().anyRequest().hasRole("USER").and().formLogin() * .permitAll().and().sessionManagement().maximumSessions(1) * .expiredUrl("/login?expired"); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * When using {@link SessionManagementConfigurer#maximumSessions(int)}, do not forget * to configure {@link HttpSessionEventPublisher} for the application to ensure that * expired sessions are cleaned up. * * In a web.xml this can be configured using the following: * * <pre> * <listener> * <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> * </listener> * </pre> * * Alternatively, * {@link AbstractSecurityWebApplicationInitializer#enableHttpSessionEventPublisher()} * could return true. * * @return the {@link SessionManagementConfigurer} for further customizations * @throws Exception */ public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception { return getOrApply(new SessionManagementConfigurer<>()); } /** * Allows configuring of Session Management. * * <h2>Example Configuration</h2> * * The following configuration demonstrates how to enforce that only a single instance * of a user is authenticated at a time. If a user authenticates with the username * "user" without logging out and an attempt to authenticate with "user" is made the * first session will be forcibly terminated and sent to the "/login?expired" URL. * * <pre> * @Configuration * @EnableWebSecurity * public class SessionManagementSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .anyRequest().hasRole("USER") * ) * .formLogin(formLogin -> * formLogin * .permitAll() * ) * .sessionManagement(sessionManagement -> * sessionManagement * .sessionConcurrency(sessionConcurrency -> * sessionConcurrency * .maximumSessions(1) * .expiredUrl("/login?expired") * ) * ); * } * } * </pre> * * When using {@link SessionManagementConfigurer#maximumSessions(int)}, do not forget * to configure {@link HttpSessionEventPublisher} for the application to ensure that * expired sessions are cleaned up. * * In a web.xml this can be configured using the following: * * <pre> * <listener> * <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> * </listener> * </pre> * * Alternatively, * {@link AbstractSecurityWebApplicationInitializer#enableHttpSessionEventPublisher()} * could return true. * * @param sessionManagementCustomizer the {@link Customizer} to provide more options for * the {@link SessionManagementConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity sessionManagement( Customizer<SessionManagementConfigurer<HttpSecurity>> sessionManagementCustomizer) throws Exception { sessionManagementCustomizer.customize(getOrApply(new SessionManagementConfigurer<>())); return HttpSecurity.this; } /** * Allows configuring a {@link PortMapper} that is available from * {@link HttpSecurity#getSharedObject(Class)}. Other provided * {@link SecurityConfigurer} objects use this configured {@link PortMapper} as a * default {@link PortMapper} when redirecting from HTTP to HTTPS or from HTTPS to * HTTP (for example when used in combination with {@link #requiresChannel()}. By * default Spring Security uses a {@link PortMapperImpl} which maps the HTTP port 8080 * to the HTTPS port 8443 and the HTTP port of 80 to the HTTPS port of 443. * * <h2>Example Configuration</h2> * * The following configuration will ensure that redirects within Spring Security from * HTTP of a port of 9090 will redirect to HTTPS port of 9443 and the HTTP port of 80 * to the HTTPS port of 443. * * <pre> * @Configuration * @EnableWebSecurity * public class PortMapperSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin() * .permitAll().and() * // Example portMapper() configuration * .portMapper().http(9090).mapsTo(9443).http(80).mapsTo(443); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * @return the {@link PortMapperConfigurer} for further customizations * @throws Exception * @see #requiresChannel() */ public PortMapperConfigurer<HttpSecurity> portMapper() throws Exception { return getOrApply(new PortMapperConfigurer<>()); } /** * Allows configuring a {@link PortMapper} that is available from * {@link HttpSecurity#getSharedObject(Class)}. Other provided * {@link SecurityConfigurer} objects use this configured {@link PortMapper} as a * default {@link PortMapper} when redirecting from HTTP to HTTPS or from HTTPS to * HTTP (for example when used in combination with {@link #requiresChannel()}. By * default Spring Security uses a {@link PortMapperImpl} which maps the HTTP port 8080 * to the HTTPS port 8443 and the HTTP port of 80 to the HTTPS port of 443. * * <h2>Example Configuration</h2> * * The following configuration will ensure that redirects within Spring Security from * HTTP of a port of 9090 will redirect to HTTPS port of 9443 and the HTTP port of 80 * to the HTTPS port of 443. * * <pre> * @Configuration * @EnableWebSecurity * public class PortMapperSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .requiresChannel(requiresChannel -> * requiresChannel * .anyRequest().requiresSecure() * ) * .portMapper(portMapper -> * portMapper * .http(9090).mapsTo(9443) * .http(80).mapsTo(443) * ); * } * } * </pre> * * @see #requiresChannel() * @param portMapperCustomizer the {@link Customizer} to provide more options for * the {@link PortMapperConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity portMapper(Customizer<PortMapperConfigurer<HttpSecurity>> portMapperCustomizer) throws Exception { portMapperCustomizer.customize(getOrApply(new PortMapperConfigurer<>())); return HttpSecurity.this; } /** * Configures container based pre authentication. In this case, authentication * is managed by the Servlet Container. * * <h2>Example Configuration</h2> * * 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}. * * <pre> * @Configuration * @EnableWebSecurity * public class JeeSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and() * // Example jee() configuration * .jee().mappableRoles("USER", "ADMIN"); * } * } * </pre> * * 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: * * <pre> * <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> * </pre> * * 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. * * @return the {@link JeeConfigurer} for further customizations * @throws Exception */ public JeeConfigurer<HttpSecurity> jee() throws Exception { return getOrApply(new JeeConfigurer<>()); } /** * Configures container based pre authentication. In this case, authentication * is managed by the Servlet Container. * * <h2>Example Configuration</h2> * * 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}. * * <pre> * @Configuration * @EnableWebSecurity * public class JeeSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .jee(jee -> * jee * .mappableRoles("USER", "ADMIN") * ); * } * } * </pre> * * 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: * * <pre> * <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> * </pre> * * 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<JeeConfigurer<HttpSecurity>> jeeCustomizer) throws Exception { jeeCustomizer.customize(getOrApply(new JeeConfigurer<>())); return HttpSecurity.this; } /** * Configures X509 based pre authentication. * * <h2>Example Configuration</h2> * * The following configuration will attempt to extract the username from the X509 * certificate. Remember that the Servlet Container will need to be configured to * request client certificates in order for this to work. * * <pre> * @Configuration * @EnableWebSecurity * public class X509SecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and() * // Example x509() configuration * .x509(); * } * } * </pre> * * @return the {@link X509Configurer} for further customizations * @throws Exception */ public X509Configurer<HttpSecurity> x509() throws Exception { return getOrApply(new X509Configurer<>()); } /** * Configures X509 based pre authentication. * * <h2>Example Configuration</h2> * * The following configuration will attempt to extract the username from the X509 * certificate. Remember that the Servlet Container will need to be configured to * request client certificates in order for this to work. * * <pre> * @Configuration * @EnableWebSecurity * public class X509SecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .x509(withDefaults()); * } * } * </pre> * * @param x509Customizer the {@link Customizer} to provide more options for * the {@link X509Configurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity x509(Customizer<X509Configurer<HttpSecurity>> x509Customizer) throws Exception { x509Customizer.customize(getOrApply(new X509Configurer<>())); return HttpSecurity.this; } /** * Allows configuring of Remember Me authentication. * * <h2>Example Configuration</h2> * * The following configuration demonstrates how to allow token based remember me * authentication. Upon authenticating if the HTTP parameter named "remember-me" * exists, then the user will be remembered even after their * {@link javax.servlet.http.HttpSession} expires. * * <pre> * @Configuration * @EnableWebSecurity * public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin() * .permitAll().and() * // Example Remember Me Configuration * .rememberMe(); * } * } * </pre> * * @return the {@link RememberMeConfigurer} for further customizations * @throws Exception */ public RememberMeConfigurer<HttpSecurity> rememberMe() throws Exception { return getOrApply(new RememberMeConfigurer<>()); } /** * Allows configuring of Remember Me authentication. * * <h2>Example Configuration</h2> * * The following configuration demonstrates how to allow token based remember me * authentication. Upon authenticating if the HTTP parameter named "remember-me" * exists, then the user will be remembered even after their * {@link javax.servlet.http.HttpSession} expires. * * <pre> * @Configuration * @EnableWebSecurity * public class RememberMeSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()) * .rememberMe(withDefaults()); * } * } * </pre> * * @param rememberMeCustomizer the {@link Customizer} to provide more options for * the {@link RememberMeConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity rememberMe(Customizer<RememberMeConfigurer<HttpSecurity>> rememberMeCustomizer) throws Exception { rememberMeCustomizer.customize(getOrApply(new RememberMeConfigurer<>())); return HttpSecurity.this; } /** * Allows restricting access based upon the {@link HttpServletRequest} using * * <h2>Example Configurations</h2> * * The most basic example is to configure all URLs to require the role "ROLE_USER". * The configuration below requires authentication to every URL and will grant access * to both the user "admin" and "user". * * <pre> * @Configuration * @EnableWebSecurity * public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER") * .and().withUser("admin").password("password").roles("ADMIN", "USER"); * } * } * </pre> * * We can also configure multiple URLs. The configuration below requires * authentication to every URL and will grant access to URLs starting with /admin/ to * only the "admin" user. All other URLs either user can access. * * <pre> * @Configuration * @EnableWebSecurity * public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN") * .antMatchers("/**").hasRole("USER").and().formLogin(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER") * .and().withUser("admin").password("password").roles("ADMIN", "USER"); * } * } * </pre> * * Note that the matchers are considered in order. Therefore, the following is invalid * because the first matcher matches every request and will never get to the second * mapping: * * <pre> * http.authorizeRequests().antMatchers("/**").hasRole("USER").antMatchers("/admin/**") * .hasRole("ADMIN") * </pre> * * @see #requestMatcher(RequestMatcher) * * @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations * @throws Exception */ public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests() throws Exception { ApplicationContext context = getContext(); return getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context)).getRegistry(); } /** * Allows restricting access based upon the {@link HttpServletRequest} using * {@link RequestMatcher} implementations (i.e. via URL patterns). * * <h2>Example Configurations</h2> * * The most basic example is to configure all URLs to require the role "ROLE_USER". * The configuration below requires authentication to every URL and will grant access * to both the user "admin" and "user". * * <pre> * @Configuration * @EnableWebSecurity * public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()); * } * } * </pre> * * We can also configure multiple URLs. The configuration below requires * authentication to every URL and will grant access to URLs starting with /admin/ to * only the "admin" user. All other URLs either user can access. * * <pre> * @Configuration * @EnableWebSecurity * public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/admin/**").hasRole("ADMIN") * .antMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()); * } * } * </pre> * * Note that the matchers are considered in order. Therefore, the following is invalid * because the first matcher matches every request and will never get to the second * mapping: * * <pre> * @Configuration * @EnableWebSecurity * public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * .antMatchers("/admin/**").hasRole("ADMIN") * ); * } * } * </pre> * * @see #requestMatcher(RequestMatcher) * * @param authorizeRequestsCustomizer the {@link Customizer} to provide more options for * the {@link ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity authorizeRequests( Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer) throws Exception { ApplicationContext context = getContext(); authorizeRequestsCustomizer .customize(getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context)).getRegistry()); return HttpSecurity.this; } /** * Allows configuring the Request Cache. For example, a protected page (/protected) * may be requested prior to authentication. The application will redirect the user to * a login page. After authentication, Spring Security will redirect the user to the * originally requested protected page (/protected). This is automatically applied * when using {@link WebSecurityConfigurerAdapter}. * * @return the {@link RequestCacheConfigurer} for further customizations * @throws Exception */ public RequestCacheConfigurer<HttpSecurity> requestCache() throws Exception { return getOrApply(new RequestCacheConfigurer<>()); } /** * Allows configuring the Request Cache. For example, a protected page (/protected) * may be requested prior to authentication. The application will redirect the user to * a login page. After authentication, Spring Security will redirect the user to the * originally requested protected page (/protected). This is automatically applied * when using {@link WebSecurityConfigurerAdapter}. * * <h2>Example Custom Configuration</h2> * * The following example demonstrates how to disable request caching. * * <pre> * @Configuration * @EnableWebSecurity * public class RequestCacheDisabledSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .requestCache(requestCache -> * requestCache.disable() * ); * } * } * </pre> * * @param requestCacheCustomizer the {@link Customizer} to provide more options for * the {@link RequestCacheConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity requestCache(Customizer<RequestCacheConfigurer<HttpSecurity>> requestCacheCustomizer) throws Exception { requestCacheCustomizer.customize(getOrApply(new RequestCacheConfigurer<>())); return HttpSecurity.this; } /** * Allows configuring exception handling. This is automatically applied when using * {@link WebSecurityConfigurerAdapter}. * * @return the {@link ExceptionHandlingConfigurer} for further customizations * @throws Exception */ public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception { return getOrApply(new ExceptionHandlingConfigurer<>()); } /** * Allows configuring exception handling. This is automatically applied when using * {@link WebSecurityConfigurerAdapter}. * * <h2>Example Custom Configuration</h2> * * The following customization will ensure that users who are denied access are forwarded * to the page "/errors/access-denied". * * <pre> * @Configuration * @EnableWebSecurity * public class ExceptionHandlingSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * // sample exception handling customization * .exceptionHandling(exceptionHandling -> * exceptionHandling * .accessDeniedPage("/errors/access-denied") * ); * } * } * </pre> * * @param exceptionHandlingCustomizer the {@link Customizer} to provide more options for * the {@link ExceptionHandlingConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity exceptionHandling( Customizer<ExceptionHandlingConfigurer<HttpSecurity>> exceptionHandlingCustomizer) throws Exception { exceptionHandlingCustomizer.customize(getOrApply(new ExceptionHandlingConfigurer<>())); return HttpSecurity.this; } /** * Sets up management of the {@link SecurityContext} on the * {@link SecurityContextHolder} between {@link HttpServletRequest}'s. This is * automatically applied when using {@link WebSecurityConfigurerAdapter}. * * @return the {@link SecurityContextConfigurer} for further customizations * @throws Exception */ public SecurityContextConfigurer<HttpSecurity> securityContext() throws Exception { 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> * @Configuration * @EnableWebSecurity * public class SecurityContextSecurityConfig extends WebSecurityConfigurerAdapter { * * @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 * {@link WebSecurityConfigurerAdapter}. * * @return the {@link ServletApiConfigurer} for further customizations * @throws Exception */ public ServletApiConfigurer<HttpSecurity> servletApi() throws Exception { return getOrApply(new ServletApiConfigurer<>()); } /** * Integrates the {@link HttpServletRequest} methods with the values found on the * {@link SecurityContext}. This is automatically applied when using * {@link WebSecurityConfigurerAdapter}. You can disable it using: * * <pre> * @Configuration * @EnableWebSecurity * public class ServletApiSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .servletApi(servletApi -> * servletApi.disable() * ); * } * } * </pre> * * @param servletApiCustomizer the {@link Customizer} to provide more options for * the {@link ServletApiConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity servletApi(Customizer<ServletApiConfigurer<HttpSecurity>> servletApiCustomizer) throws Exception { servletApiCustomizer.customize(getOrApply(new ServletApiConfigurer<>())); return HttpSecurity.this; } /** * Adds CSRF support. This is activated by default when using * {@link WebSecurityConfigurerAdapter}'s default constructor. You can disable it * using: * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .csrf().disable() * ...; * } * } * </pre> * * @return the {@link ServletApiConfigurer} for further customizations * @throws Exception */ public CsrfConfigurer<HttpSecurity> csrf() throws Exception { ApplicationContext context = getContext(); return getOrApply(new CsrfConfigurer<>(context)); } /** * Adds CSRF support. This is activated by default when using * {@link WebSecurityConfigurerAdapter}'s default constructor. You can disable it * using: * * <pre> * @Configuration * @EnableWebSecurity * public class CsrfSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .csrf(csrf -> csrf.disable()); * } * } * </pre> * * @param csrfCustomizer the {@link Customizer} to provide more options for * the {@link CsrfConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity csrf(Customizer<CsrfConfigurer<HttpSecurity>> csrfCustomizer) throws Exception { ApplicationContext context = getContext(); csrfCustomizer.customize(getOrApply(new CsrfConfigurer<>(context))); return HttpSecurity.this; } /** * Provides logout support. This is automatically applied when using * {@link WebSecurityConfigurerAdapter}. The default is that accessing the URL * "/logout" will log the user out by invalidating the HTTP Session, cleaning up any * {@link #rememberMe()} authentication that was configured, clearing the * {@link SecurityContextHolder}, and then redirect to "/login?success". * * <h2>Example Custom Configuration</h2> * * The following customization to log out when the URL "/custom-logout" is invoked. * Log out will remove the cookie named "remove", not invalidate the HttpSession, * clear the SecurityContextHolder, and upon completion redirect to "/logout-success". * * <pre> * @Configuration * @EnableWebSecurity * public class LogoutSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin() * .and() * // sample logout customization * .logout().deleteCookies("remove").invalidateHttpSession(false) * .logoutUrl("/custom-logout").logoutSuccessUrl("/logout-success"); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * @return the {@link LogoutConfigurer} for further customizations * @throws Exception */ public LogoutConfigurer<HttpSecurity> logout() throws Exception { return getOrApply(new LogoutConfigurer<>()); } /** * Provides logout support. This is automatically applied when using * {@link WebSecurityConfigurerAdapter}. The default is that accessing the URL * "/logout" will log the user out by invalidating the HTTP Session, cleaning up any * {@link #rememberMe()} authentication that was configured, clearing the * {@link SecurityContextHolder}, and then redirect to "/login?success". * * <h2>Example Custom Configuration</h2> * * The following customization to log out when the URL "/custom-logout" is invoked. * Log out will remove the cookie named "remove", not invalidate the HttpSession, * clear the SecurityContextHolder, and upon completion redirect to "/logout-success". * * <pre> * @Configuration * @EnableWebSecurity * public class LogoutSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()) * // sample logout customization * .logout(logout -> * logout.deleteCookies("remove") * .invalidateHttpSession(false) * .logoutUrl("/custom-logout") * .logoutSuccessUrl("/logout-success") * ); * } * } * </pre> * * @param logoutCustomizer the {@link Customizer} to provide more options for * the {@link LogoutConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity logout(Customizer<LogoutConfigurer<HttpSecurity>> logoutCustomizer) throws Exception { logoutCustomizer.customize(getOrApply(new LogoutConfigurer<>())); return HttpSecurity.this; } /** * Allows configuring how an anonymous user is represented. This is automatically * applied when used in conjunction with {@link WebSecurityConfigurerAdapter}. By * default anonymous users will be represented with an * {@link org.springframework.security.authentication.AnonymousAuthenticationToken} * and contain the role "ROLE_ANONYMOUS". * * <h2>Example Configuration</h2> * * The following configuration demonstrates how to specify that anonymous users should * contain the role "ROLE_ANON" instead. * * <pre> * @Configuration * @EnableWebSecurity * public class AnononymousSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin() * .and() * // sample anonymous customization * .anonymous().authorities("ROLE_ANON"); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * The following demonstrates how to represent anonymous users as null. Note that this * can cause {@link NullPointerException} in code that assumes anonymous * authentication is enabled. * * <pre> * @Configuration * @EnableWebSecurity * public class AnononymousSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin() * .and() * // sample anonymous customization * .anonymous().disabled(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * @return the {@link AnonymousConfigurer} for further customizations * @throws Exception */ public AnonymousConfigurer<HttpSecurity> anonymous() throws Exception { return getOrApply(new AnonymousConfigurer<>()); } /** * Allows configuring how an anonymous user is represented. This is automatically * applied when used in conjunction with {@link WebSecurityConfigurerAdapter}. By * default anonymous users will be represented with an * {@link org.springframework.security.authentication.AnonymousAuthenticationToken} * and contain the role "ROLE_ANONYMOUS". * * <h2>Example Configuration</h2> * * The following configuration demonstrates how to specify that anonymous users should * contain the role "ROLE_ANON" instead. * * <pre> * @Configuration * @EnableWebSecurity * public class AnononymousSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()) * // sample anonymous customization * .anonymous(anonymous -> * anonymous * .authorities("ROLE_ANON") * ) * } * } * </pre> * * The following demonstrates how to represent anonymous users as null. Note that this * can cause {@link NullPointerException} in code that assumes anonymous * authentication is enabled. * * <pre> * @Configuration * @EnableWebSecurity * public class AnonymousSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()) * // sample anonymous customization * .anonymous(anonymous -> * anonymous.disabled() * ); * } * } * </pre> * * @param anonymousCustomizer the {@link Customizer} to provide more options for * the {@link AnonymousConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity anonymous(Customizer<AnonymousConfigurer<HttpSecurity>> anonymousCustomizer) throws Exception { anonymousCustomizer.customize(getOrApply(new AnonymousConfigurer<>())); return HttpSecurity.this; } /** * Specifies to support form based authentication. If * {@link FormLoginConfigurer#loginPage(String)} is not specified a default login page * will be generated. * * <h2>Example Configurations</h2> * * The most basic configuration defaults to automatically generating a login page at * the URL "/login", redirecting to "/login?error" for authentication failure. The * details of the login page can be found on * {@link FormLoginConfigurer#loginPage(String)} * * <pre> * @Configuration * @EnableWebSecurity * public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * The configuration below demonstrates customizing the defaults. * * <pre> * @Configuration * @EnableWebSecurity * public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin() * .usernameParameter("username") // default is username * .passwordParameter("password") // default is password * .loginPage("/authentication/login") // default is /login with an HTTP get * .failureUrl("/authentication/login?failed") // default is /login?error * .loginProcessingUrl("/authentication/login/process"); // default is /login * // with an HTTP * // post * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * @see FormLoginConfigurer#loginPage(String) * * @return the {@link FormLoginConfigurer} for further customizations * @throws Exception */ public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception { return getOrApply(new FormLoginConfigurer<>()); } /** * Specifies to support form based authentication. If * {@link FormLoginConfigurer#loginPage(String)} is not specified a default login page * will be generated. * * <h2>Example Configurations</h2> * * The most basic configuration defaults to automatically generating a login page at * the URL "/login", redirecting to "/login?error" for authentication failure. The * details of the login page can be found on * {@link FormLoginConfigurer#loginPage(String)} * * <pre> * @Configuration * @EnableWebSecurity * public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()); * } * } * </pre> * * The configuration below demonstrates customizing the defaults. * * <pre> * @Configuration * @EnableWebSecurity * public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .formLogin(formLogin -> * formLogin * .usernameParameter("username") * .passwordParameter("password") * .loginPage("/authentication/login") * .failureUrl("/authentication/login?failed") * .loginProcessingUrl("/authentication/login/process") * ); * } * } * </pre> * * @see FormLoginConfigurer#loginPage(String) * * @param formLoginCustomizer the {@link Customizer} to provide more options for * the {@link FormLoginConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception { formLoginCustomizer.customize(getOrApply(new FormLoginConfigurer<>())); return HttpSecurity.this; } /** * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider. * <br> * <br> * * The "authentication flow" is implemented using the <b>Authorization Code Grant</b>, as specified in the * <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">OAuth 2.0 Authorization Framework</a> * and <a target="_blank" href="https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">OpenID Connect Core 1.0</a> * specification. * <br> * <br> * * As a prerequisite to using this feature, you must register a client with a provider. * The client registration information may than be used for configuring * a {@link org.springframework.security.oauth2.client.registration.ClientRegistration} using a * {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder}. * <br> * <br> * * {@link org.springframework.security.oauth2.client.registration.ClientRegistration}(s) are composed within a * {@link org.springframework.security.oauth2.client.registration.ClientRegistrationRepository}, * which is <b>required</b> and must be registered with the {@link ApplicationContext} or * configured via <code>oauth2Login().clientRegistrationRepository(..)</code>. * <br> * <br> * * The default configuration provides an auto-generated login page at <code>"/login"</code> and * redirects to <code>"/login?error"</code> when an authentication error occurs. * The login page will display each of the clients with a link * that is capable of initiating the "authentication flow". * <br> * <br> * * <p> * <h2>Example Configuration</h2> * * The following example shows the minimal configuration required, using Google as the Authentication Provider. * * <pre> * @Configuration * public class OAuth2LoginConfig { * * @EnableWebSecurity * public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests() * .anyRequest().authenticated() * .and() * .oauth2Login(); * } * } * * @Bean * public ClientRegistrationRepository clientRegistrationRepository() { * return new InMemoryClientRegistrationRepository(this.googleClientRegistration()); * } * * private ClientRegistration googleClientRegistration() { * return ClientRegistration.withRegistrationId("google") * .clientId("google-client-id") * .clientSecret("google-client-secret") * .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC) * .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) * .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}") * .scope("openid", "profile", "email", "address", "phone") * .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth") * .tokenUri("https://www.googleapis.com/oauth2/v4/token") * .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo") * .userNameAttributeName(IdTokenClaimNames.SUB) * .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs") * .clientName("Google") * .build(); * } * } * </pre> * * <p> * For more advanced configuration, see {@link OAuth2LoginConfigurer} for available options to customize the defaults. * * @since 5.0 * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant</a> * @see <a target="_blank" href="https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">Section 3.1 Authorization Code Flow</a> * @see org.springframework.security.oauth2.client.registration.ClientRegistration * @see org.springframework.security.oauth2.client.registration.ClientRegistrationRepository * @return the {@link OAuth2LoginConfigurer} for further customizations * @throws Exception */ public OAuth2LoginConfigurer<HttpSecurity> oauth2Login() throws Exception { return getOrApply(new OAuth2LoginConfigurer<>()); } /** * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider. * <br> * <br> * * The "authentication flow" is implemented using the <b>Authorization Code Grant</b>, as specified in the * <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">OAuth 2.0 Authorization Framework</a> * and <a target="_blank" href="https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">OpenID Connect Core 1.0</a> * specification. * <br> * <br> * * As a prerequisite to using this feature, you must register a client with a provider. * The client registration information may than be used for configuring * a {@link org.springframework.security.oauth2.client.registration.ClientRegistration} using a * {@link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder}. * <br> * <br> * * {@link org.springframework.security.oauth2.client.registration.ClientRegistration}(s) are composed within a * {@link org.springframework.security.oauth2.client.registration.ClientRegistrationRepository}, * which is <b>required</b> and must be registered with the {@link ApplicationContext} or * configured via <code>oauth2Login().clientRegistrationRepository(..)</code>. * <br> * <br> * * The default configuration provides an auto-generated login page at <code>"/login"</code> and * redirects to <code>"/login?error"</code> when an authentication error occurs. * The login page will display each of the clients with a link * that is capable of initiating the "authentication flow". * <br> * <br> * * <p> * <h2>Example Configuration</h2> * * The following example shows the minimal configuration required, using Google as the Authentication Provider. * * <pre> * @Configuration * public class OAuth2LoginConfig { * * @EnableWebSecurity * public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .anyRequest().authenticated() * ) * .oauth2Login(withDefaults()); * } * } * * @Bean * public ClientRegistrationRepository clientRegistrationRepository() { * return new InMemoryClientRegistrationRepository(this.googleClientRegistration()); * } * * private ClientRegistration googleClientRegistration() { * return ClientRegistration.withRegistrationId("google") * .clientId("google-client-id") * .clientSecret("google-client-secret") * .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC) * .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) * .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}") * .scope("openid", "profile", "email", "address", "phone") * .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth") * .tokenUri("https://www.googleapis.com/oauth2/v4/token") * .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo") * .userNameAttributeName(IdTokenClaimNames.SUB) * .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs") * .clientName("Google") * .build(); * } * } * </pre> * * <p> * For more advanced configuration, see {@link OAuth2LoginConfigurer} for available options to customize the defaults. * * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant</a> * @see <a target="_blank" href="https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">Section 3.1 Authorization Code Flow</a> * @see org.springframework.security.oauth2.client.registration.ClientRegistration * @see org.springframework.security.oauth2.client.registration.ClientRegistrationRepository * * @param oauth2LoginCustomizer the {@link Customizer} to provide more options for * the {@link OAuth2LoginConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity oauth2Login(Customizer<OAuth2LoginConfigurer<HttpSecurity>> oauth2LoginCustomizer) throws Exception { oauth2LoginCustomizer.customize(getOrApply(new OAuth2LoginConfigurer<>())); return HttpSecurity.this; } /** * Configures OAuth 2.0 Client support. * * @since 5.1 * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-1.1">OAuth 2.0 Authorization Framework</a> * @return the {@link OAuth2ClientConfigurer} for further customizations * @throws Exception */ public OAuth2ClientConfigurer<HttpSecurity> oauth2Client() throws Exception { OAuth2ClientConfigurer<HttpSecurity> configurer = getOrApply(new OAuth2ClientConfigurer<>()); this.postProcess(configurer); return configurer; } /** * Configures OAuth 2.0 Client support. * * <h2>Example Configuration</h2> * * The following example demonstrates how to enable OAuth 2.0 Client support for all endpoints. * * <pre> * @Configuration * @EnableWebSecurity * public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter { * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .anyRequest().authenticated() * ) * .oauth2Client(withDefaults()); * } * } * </pre> * * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-1.1">OAuth 2.0 Authorization Framework</a> * * @param oauth2ClientCustomizer the {@link Customizer} to provide more options for * the {@link OAuth2ClientConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity oauth2Client(Customizer<OAuth2ClientConfigurer<HttpSecurity>> oauth2ClientCustomizer) throws Exception { oauth2ClientCustomizer.customize(getOrApply(new OAuth2ClientConfigurer<>())); return HttpSecurity.this; } /** * Configures OAuth 2.0 Resource Server support. * * @since 5.1 * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-1.1">OAuth 2.0 Authorization Framework</a> * @return the {@link OAuth2ResourceServerConfigurer} for further customizations * @throws Exception */ public OAuth2ResourceServerConfigurer<HttpSecurity> oauth2ResourceServer() throws Exception { OAuth2ResourceServerConfigurer<HttpSecurity> configurer = getOrApply( new OAuth2ResourceServerConfigurer<>(getContext())); this.postProcess(configurer); return configurer; } /** * Configures OAuth 2.0 Resource Server support. * * <h2>Example Configuration</h2> * * The following example demonstrates how to configure a custom JWT authentication converter. * * <pre> * @Configuration * @EnableWebSecurity * public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter { * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .anyRequest().authenticated() * ) * .oauth2ResourceServer(oauth2ResourceServer -> * oauth2ResourceServer * .jwt(jwt -> * jwt * .jwtAuthenticationConverter(jwtDecoder()) * ) * ); * } * * @Bean * public JwtDecoder jwtDecoder() { * return JwtDecoders.fromOidcIssuerLocation(issuerUri); * } * } * </pre> * * @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-1.1">OAuth 2.0 Authorization Framework</a> * * @param oauth2ResourceServerCustomizer the {@link Customizer} to provide more options for * the {@link OAuth2ResourceServerConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity oauth2ResourceServer( Customizer<OAuth2ResourceServerConfigurer<HttpSecurity>> oauth2ResourceServerCustomizer) throws Exception { OAuth2ResourceServerConfigurer<HttpSecurity> configurer = getOrApply( new OAuth2ResourceServerConfigurer<>(getContext())); this.postProcess(configurer); oauth2ResourceServerCustomizer.customize(configurer); return HttpSecurity.this; } /** * Configures channel security. In order for this configuration to be useful at least * one mapping to a required channel must be provided. * * <h2>Example Configuration</h2> * * The example below demonstrates how to require HTTPs for every request. Only * requiring HTTPS for some requests is supported, but not recommended since an * application that allows for HTTP introduces many security vulnerabilities. For one * such example, read about <a * href="https://en.wikipedia.org/wiki/Firesheep">Firesheep</a>. * * <pre> * @Configuration * @EnableWebSecurity * public class ChannelSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin() * .and().requiresChannel().anyRequest().requiresSecure(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * * @return the {@link ChannelSecurityConfigurer} for further customizations * @throws Exception */ public ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry requiresChannel() throws Exception { ApplicationContext context = getContext(); return getOrApply(new ChannelSecurityConfigurer<>(context)).getRegistry(); } /** * Configures channel security. In order for this configuration to be useful at least * one mapping to a required channel must be provided. * * <h2>Example Configuration</h2> * * The example below demonstrates how to require HTTPs for every request. Only * requiring HTTPS for some requests is supported, but not recommended since an * application that allows for HTTP introduces many security vulnerabilities. For one * such example, read about <a * href="https://en.wikipedia.org/wiki/Firesheep">Firesheep</a>. * * <pre> * @Configuration * @EnableWebSecurity * public class ChannelSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .formLogin(withDefaults()) * .requiresChannel(requiresChannel -> * requiresChannel * .anyRequest().requiresSecure() * ); * } * } * </pre> * * @param requiresChannelCustomizer the {@link Customizer} to provide more options for * the {@link ChannelSecurityConfigurer.ChannelRequestMatcherRegistry} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity requiresChannel( Customizer<ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry> requiresChannelCustomizer) throws Exception { ApplicationContext context = getContext(); requiresChannelCustomizer.customize(getOrApply(new ChannelSecurityConfigurer<>(context)).getRegistry()); return HttpSecurity.this; } /** * Configures HTTP Basic authentication. * * <h2>Example Configuration</h2> * * The example below demonstrates how to configure HTTP Basic authentication for an * application. The default realm is "Realm", but can be * customized using {@link HttpBasicConfigurer#realmName(String)}. * * <pre> * @Configuration * @EnableWebSecurity * public class HttpBasicSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http.authorizeRequests().antMatchers("/**").hasRole("USER").and().httpBasic(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); * } * } * </pre> * * @return the {@link HttpBasicConfigurer} for further customizations * @throws Exception */ public HttpBasicConfigurer<HttpSecurity> httpBasic() throws Exception { return getOrApply(new HttpBasicConfigurer<>()); } /** * Configures HTTP Basic authentication. * * <h2>Example Configuration</h2> * * The example below demonstrates how to configure HTTP Basic authentication for an * application. The default realm is "Realm", but can be * customized using {@link HttpBasicConfigurer#realmName(String)}. * * <pre> * @Configuration * @EnableWebSecurity * public class HttpBasicSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .httpBasic(withDefaults()); * } * } * </pre> * * @param httpBasicCustomizer the {@link Customizer} to provide more options for * the {@link HttpBasicConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity httpBasic(Customizer<HttpBasicConfigurer<HttpSecurity>> httpBasicCustomizer) throws Exception { httpBasicCustomizer.customize(getOrApply(new HttpBasicConfigurer<>())); return HttpSecurity.this; } public <C> void setSharedObject(Class<C> sharedType, C object) { super.setSharedObject(sharedType, object); } @Override protected void beforeConfigure() throws Exception { setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build()); } @Override protected DefaultSecurityFilterChain performBuild() throws Exception { Collections.sort(filters, comparator); return new DefaultSecurityFilterChain(requestMatcher, filters); } /* * (non-Javadoc) * * @see * org.springframework.security.config.annotation.web.HttpSecurityBuilder#authenticationProvider * (org.springframework.security.authentication.AuthenticationProvider) */ public HttpSecurity authenticationProvider(AuthenticationProvider authenticationProvider) { getAuthenticationRegistry().authenticationProvider(authenticationProvider); return this; } /* * (non-Javadoc) * * @see * org.springframework.security.config.annotation.web.HttpSecurityBuilder#userDetailsService * (org.springframework.security.core.userdetails.UserDetailsService) */ public HttpSecurity userDetailsService(UserDetailsService userDetailsService) throws Exception { getAuthenticationRegistry().userDetailsService(userDetailsService); return this; } private AuthenticationManagerBuilder getAuthenticationRegistry() { return getSharedObject(AuthenticationManagerBuilder.class); } /* * (non-Javadoc) * * @see * org.springframework.security.config.annotation.web.HttpSecurityBuilder#addFilterAfter(javax * .servlet.Filter, java.lang.Class) */ public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) { comparator.registerAfter(filter.getClass(), afterFilter); return addFilter(filter); } /* * (non-Javadoc) * * @see * org.springframework.security.config.annotation.web.HttpSecurityBuilder#addFilterBefore( * javax.servlet.Filter, java.lang.Class) */ public HttpSecurity addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) { comparator.registerBefore(filter.getClass(), beforeFilter); return addFilter(filter); } /* * (non-Javadoc) * * @see * org.springframework.security.config.annotation.web.HttpSecurityBuilder#addFilter(javax. * servlet.Filter) */ public HttpSecurity addFilter(Filter filter) { Class<? extends Filter> filterClass = filter.getClass(); if (!comparator.isRegistered(filterClass)) { throw new IllegalArgumentException("The Filter class " + filterClass.getName() + " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead."); } this.filters.add(filter); return this; } /** * Adds the Filter at the location of the specified Filter class. For example, if you * want the filter CustomFilter to be registered in the same position as * {@link UsernamePasswordAuthenticationFilter}, you can invoke: * * <pre> * addFilterAt(new CustomFilter(), UsernamePasswordAuthenticationFilter.class) * </pre> * * Registration of multiple Filters in the same location means their ordering is not * deterministic. More concretely, registering multiple Filters in the same location * does not override existing Filters. Instead, do not register Filters you do not * want to use. * * @param filter the Filter to register * @param atFilter the location of another {@link Filter} that is already registered * (i.e. known) with Spring Security. * @return the {@link HttpSecurity} for further customizations */ public HttpSecurity addFilterAt(Filter filter, Class<? extends Filter> atFilter) { this.comparator.registerAt(filter.getClass(), atFilter); return addFilter(filter); } /** * Allows specifying which {@link HttpServletRequest} instances this * {@link HttpSecurity} will be invoked on. This method allows for easily invoking the * {@link HttpSecurity} for multiple different {@link RequestMatcher} instances. If * only a single {@link RequestMatcher} is necessary consider using {@link #mvcMatcher(String)}, * {@link #antMatcher(String)}, {@link #regexMatcher(String)}, or * {@link #requestMatcher(RequestMatcher)}. * * <p> * Invoking {@link #requestMatchers()} will not override previous invocations of {@link #mvcMatcher(String)}}, * {@link #requestMatchers()}, {@link #antMatcher(String)}, * {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}. * </p> * * <h3>Example Configurations</h3> * * The following configuration enables the {@link HttpSecurity} for URLs that begin * with "/api/" or "/oauth/". * * <pre> * @Configuration * @EnableWebSecurity * public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .requestMatchers() * .antMatchers("/api/**", "/oauth/**") * .and() * .authorizeRequests() * .antMatchers("/**").hasRole("USER") * .and() * .httpBasic(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth * .inMemoryAuthentication() * .withUser("user").password("password").roles("USER"); * } * } * </pre> * * The configuration below is the same as the previous configuration. * * <pre> * @Configuration * @EnableWebSecurity * public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .requestMatchers() * .antMatchers("/api/**") * .antMatchers("/oauth/**") * .and() * .authorizeRequests() * .antMatchers("/**").hasRole("USER") * .and() * .httpBasic(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth * .inMemoryAuthentication() * .withUser("user").password("password").roles("USER"); * } * } * </pre> * * The configuration below is also the same as the above configuration. * * <pre> * @Configuration * @EnableWebSecurity * public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .requestMatchers() * .antMatchers("/api/**") * .and() * .requestMatchers() * .antMatchers("/oauth/**") * .and() * .authorizeRequests() * .antMatchers("/**").hasRole("USER") * .and() * .httpBasic(); * } * * @Override * protected void configure(AuthenticationManagerBuilder auth) throws Exception { * auth * .inMemoryAuthentication() * .withUser("user").password("password").roles("USER"); * } * } * </pre> * * @return the {@link RequestMatcherConfigurer} for further customizations */ public RequestMatcherConfigurer requestMatchers() { return requestMatcherConfigurer; } /** * Allows specifying which {@link HttpServletRequest} instances this * {@link HttpSecurity} will be invoked on. This method allows for easily invoking the * {@link HttpSecurity} for multiple different {@link RequestMatcher} instances. If * only a single {@link RequestMatcher} is necessary consider using {@link #mvcMatcher(String)}, * {@link #antMatcher(String)}, {@link #regexMatcher(String)}, or * {@link #requestMatcher(RequestMatcher)}. * * <p> * Invoking {@link #requestMatchers()} will not override previous invocations of {@link #mvcMatcher(String)}}, * {@link #requestMatchers()}, {@link #antMatcher(String)}, * {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}. * </p> * * <h3>Example Configurations</h3> * * The following configuration enables the {@link HttpSecurity} for URLs that begin * with "/api/" or "/oauth/". * * <pre> * @Configuration * @EnableWebSecurity * public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .requestMatchers(requestMatchers -> * requestMatchers * .antMatchers("/api/**", "/oauth/**") * ) * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .httpBasic(withDefaults()); * } * } * </pre> * * The configuration below is the same as the previous configuration. * * <pre> * @Configuration * @EnableWebSecurity * public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .requestMatchers(requestMatchers -> * requestMatchers * .antMatchers("/api/**") * .antMatchers("/oauth/**") * ) * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .httpBasic(withDefaults()); * } * } * </pre> * * The configuration below is also the same as the above configuration. * * <pre> * @Configuration * @EnableWebSecurity * public class RequestMatchersSecurityConfig extends WebSecurityConfigurerAdapter { * * @Override * protected void configure(HttpSecurity http) throws Exception { * http * .requestMatchers(requestMatchers -> * requestMatchers * .antMatchers("/api/**") * ) * .requestMatchers(requestMatchers -> * requestMatchers * .antMatchers("/oauth/**") * ) * .authorizeRequests(authorizeRequests -> * authorizeRequests * .antMatchers("/**").hasRole("USER") * ) * .httpBasic(withDefaults()); * } * } * </pre> * * @param requestMatcherCustomizer the {@link Customizer} to provide more options for * the {@link RequestMatcherConfigurer} * @return the {@link HttpSecurity} for further customizations * @throws Exception */ public HttpSecurity requestMatchers(Customizer<RequestMatcherConfigurer> requestMatcherCustomizer) throws Exception { requestMatcherCustomizer.customize(requestMatcherConfigurer); return HttpSecurity.this; } /** * Allows configuring the {@link HttpSecurity} to only be invoked when matching the * provided {@link RequestMatcher}. If more advanced configuration is necessary, * consider using {@link #requestMatchers()}. * * <p> * Invoking {@link #requestMatcher(RequestMatcher)} will override previous invocations * of {@link #requestMatchers()}, {@link #mvcMatcher(String)}, {@link #antMatcher(String)}, * {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}. * </p> * * @param requestMatcher the {@link RequestMatcher} to use (i.e. new * AntPathRequestMatcher("/admin/**","GET") ) * @return the {@link HttpSecurity} for further customizations * @see #requestMatchers() * @see #antMatcher(String) * @see #regexMatcher(String) */ public HttpSecurity requestMatcher(RequestMatcher requestMatcher) { this.requestMatcher = requestMatcher; return this; } /** * Allows configuring the {@link HttpSecurity} to only be invoked when matching the * provided ant pattern. If more advanced configuration is necessary, consider using * {@link #requestMatchers()} or {@link #requestMatcher(RequestMatcher)}. * * <p> * Invoking {@link #antMatcher(String)} will override previous invocations of {@link #mvcMatcher(String)}}, * {@link #requestMatchers()}, {@link #antMatcher(String)}, * {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}. * </p> * * @param antPattern the Ant Pattern to match on (i.e. "/admin/**") * @return the {@link HttpSecurity} for further customizations * @see AntPathRequestMatcher */ public HttpSecurity antMatcher(String antPattern) { return requestMatcher(new AntPathRequestMatcher(antPattern)); } /** * Allows configuring the {@link HttpSecurity} to only be invoked when matching the * provided Spring MVC pattern. If more advanced configuration is necessary, consider using * {@link #requestMatchers()} or {@link #requestMatcher(RequestMatcher)}. * * <p> * Invoking {@link #mvcMatcher(String)} will override previous invocations of {@link #mvcMatcher(String)}}, * {@link #requestMatchers()}, {@link #antMatcher(String)}, * {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}. * </p> * * @param mvcPattern the Spring MVC Pattern to match on (i.e. "/admin/**") * @return the {@link HttpSecurity} for further customizations * @see MvcRequestMatcher */ public HttpSecurity mvcMatcher(String mvcPattern) { HandlerMappingIntrospector introspector = new HandlerMappingIntrospector(getContext()); return requestMatcher(new MvcRequestMatcher(introspector, mvcPattern)); } /** * Allows configuring the {@link HttpSecurity} to only be invoked when matching the * provided regex pattern. If more advanced configuration is necessary, consider using * {@link #requestMatchers()} or {@link #requestMatcher(RequestMatcher)}. * * <p> * Invoking {@link #regexMatcher(String)} will override previous invocations of {@link #mvcMatcher(String)}}, * {@link #requestMatchers()}, {@link #antMatcher(String)}, * {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}. * </p> * * @param pattern the Regular Expression to match on (i.e. "/admin/.+") * @return the {@link HttpSecurity} for further customizations * @see RegexRequestMatcher */ public HttpSecurity regexMatcher(String pattern) { return requestMatcher(new RegexRequestMatcher(pattern, null)); } /** * An extension to {@link RequestMatcherConfigurer} that allows optionally configuring * the servlet path. * * @author Rob Winch */ public final class MvcMatchersRequestMatcherConfigurer extends RequestMatcherConfigurer { /** * Creates a new instance * @param context the {@link ApplicationContext} to use * @param matchers the {@link MvcRequestMatcher} instances to set the servlet path * on if {@link #servletPath(String)} is set. */ private MvcMatchersRequestMatcherConfigurer(ApplicationContext context, List<MvcRequestMatcher> matchers) { super(context); this.matchers = new ArrayList<>(matchers); } public RequestMatcherConfigurer servletPath(String servletPath) { for (RequestMatcher matcher : this.matchers) { ((MvcRequestMatcher) matcher).setServletPath(servletPath); } return this; } } /** * Allows mapping HTTP requests that this {@link HttpSecurity} will be used for * * @author Rob Winch * @since 3.2 */ public class RequestMatcherConfigurer extends AbstractRequestMatcherRegistry<RequestMatcherConfigurer> { protected List<RequestMatcher> matchers = new ArrayList<>(); /** * @param context */ private RequestMatcherConfigurer(ApplicationContext context) { setApplicationContext(context); } @Override public MvcMatchersRequestMatcherConfigurer mvcMatchers(HttpMethod method, String... mvcPatterns) { List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns); setMatchers(mvcMatchers); return new MvcMatchersRequestMatcherConfigurer(getContext(), mvcMatchers); } @Override public MvcMatchersRequestMatcherConfigurer mvcMatchers(String... patterns) { return mvcMatchers(null, patterns); } @Override protected RequestMatcherConfigurer chainRequestMatchers(List<RequestMatcher> requestMatchers) { setMatchers(requestMatchers); return this; } private void setMatchers(List<? extends RequestMatcher> requestMatchers) { this.matchers.addAll(requestMatchers); requestMatcher(new OrRequestMatcher(this.matchers)); } /** * Return the {@link HttpSecurity} for further customizations * * @return the {@link HttpSecurity} for further customizations */ public HttpSecurity and() { return HttpSecurity.this; } } /** * If the {@link SecurityConfigurer} has already been specified get the original, * otherwise apply the new {@link SecurityConfigurerAdapter}. * * @param configurer the {@link SecurityConfigurer} to apply if one is not found for * this {@link SecurityConfigurer} class. * @return the current {@link SecurityConfigurer} for the configurer passed in * @throws Exception */ @SuppressWarnings("unchecked") private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply( C configurer) throws Exception { C existingConfig = (C) getConfigurer(configurer.getClass()); if (existingConfig != null) { return existingConfig; } return apply(configurer); } }