> formLoginCustomizer) throws Exception {
+ formLoginCustomizer.customize(getOrApply(new FormLoginConfigurer<>()));
+ return HttpSecurity.this;
}
/**
@@ -993,6 +1951,103 @@ public final class HttpSecurity extends
return getOrApply(new OAuth2LoginConfigurer<>());
}
+ /**
+ * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider.
+ *
+ *
+ *
+ * The "authentication flow" is implemented using the Authorization Code Grant, as specified in the
+ * OAuth 2.0 Authorization Framework
+ * and OpenID Connect Core 1.0
+ * specification.
+ *
+ *
+ *
+ * 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}.
+ *
+ *
+ *
+ * {@link org.springframework.security.oauth2.client.registration.ClientRegistration}(s) are composed within a
+ * {@link org.springframework.security.oauth2.client.registration.ClientRegistrationRepository},
+ * which is required and must be registered with the {@link ApplicationContext} or
+ * configured via oauth2Login().clientRegistrationRepository(..).
+ *
+ *
+ *
+ * The default configuration provides an auto-generated login page at "/login" and
+ * redirects to "/login?error" 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".
+ *
+ *
+ *
+ *
+ *
Example Configuration
+ *
+ * The following example shows the minimal configuration required, using Google as the Authentication Provider.
+ *
+ *
+ * @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();
+ * }
+ * }
+ *
+ *
+ *
+ * For more advanced configuration, see {@link OAuth2LoginConfigurer} for available options to customize the defaults.
+ *
+ * @see Section 4.1 Authorization Code Grant
+ * @see Section 3.1 Authorization Code Flow
+ * @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> oauth2LoginCustomizer) throws Exception {
+ oauth2LoginCustomizer.customize(getOrApply(new OAuth2LoginConfigurer<>()));
+ return HttpSecurity.this;
+ }
+
/**
* Configures OAuth 2.0 Client support.
*
@@ -1007,6 +2062,41 @@ public final class HttpSecurity extends
return configurer;
}
+ /**
+ * Configures OAuth 2.0 Client support.
+ *
+ * Example Configuration
+ *
+ * The following example demonstrates how to enable OAuth 2.0 Client support for all endpoints.
+ *
+ *
+ * @Configuration
+ * @EnableWebSecurity
+ * public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
+ * @Override
+ * protected void configure(HttpSecurity http) throws Exception {
+ * http
+ * .authorizeRequests(authorizeRequests ->
+ * authorizeRequests
+ * .anyRequest().authenticated()
+ * )
+ * .oauth2Client(withDefaults());
+ * }
+ * }
+ *
+ *
+ * @see OAuth 2.0 Authorization Framework
+ *
+ * @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> oauth2ClientCustomizer) throws Exception {
+ oauth2ClientCustomizer.customize(getOrApply(new OAuth2ClientConfigurer<>()));
+ return HttpSecurity.this;
+ }
+
/**
* Configures OAuth 2.0 Resource Server support.
*
@@ -1021,6 +2111,55 @@ public final class HttpSecurity extends
return configurer;
}
+ /**
+ * Configures OAuth 2.0 Resource Server support.
+ *
+ * Example Configuration
+ *
+ * The following example demonstrates how to configure a custom JWT authentication converter.
+ *
+ *
+ * @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);
+ * }
+ * }
+ *
+ *
+ * @see OAuth 2.0 Authorization Framework
+ *
+ * @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> oauth2ResourceServerCustomizer)
+ throws Exception {
+ OAuth2ResourceServerConfigurer 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.
@@ -1062,6 +2201,52 @@ public final class HttpSecurity extends
.getRegistry();
}
+ /**
+ * Configures channel security. In order for this configuration to be useful at least
+ * one mapping to a required channel must be provided.
+ *
+ * Example Configuration
+ *
+ * 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 Firesheep.
+ *
+ *
+ * @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()
+ * );
+ * }
+ * }
+ *
+ *
+ * @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.ChannelRequestMatcherRegistry> requiresChannelCustomizer)
+ throws Exception {
+ ApplicationContext context = getContext();
+ requiresChannelCustomizer.customize(getOrApply(new ChannelSecurityConfigurer<>(context))
+ .getRegistry());
+ return HttpSecurity.this;
+ }
+
/**
* Configures HTTP Basic authentication.
*
@@ -1112,9 +2297,10 @@ public final class HttpSecurity extends
* @Override
* protected void configure(HttpSecurity http) throws Exception {
* http
- * .authorizeRequests()
- * .antMatchers("/**").hasRole("USER")
- * .and()
+ * .authorizeRequests(authorizeRequests ->
+ * authorizeRequests
+ * .antMatchers("/**").hasRole("USER")
+ * )
* .httpBasic(withDefaults());
* }
* }
@@ -1354,6 +2540,107 @@ public final class HttpSecurity extends
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)}.
+ *
+ *
+ * Invoking {@link #requestMatchers()} will not override previous invocations of {@link #mvcMatcher(String)}},
+ * {@link #requestMatchers()}, {@link #antMatcher(String)},
+ * {@link #regexMatcher(String)}, and {@link #requestMatcher(RequestMatcher)}.
+ *
+ *
+ * Example Configurations
+ *
+ * The following configuration enables the {@link HttpSecurity} for URLs that begin
+ * with "/api/" or "/oauth/".
+ *
+ *
+ * @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());
+ * }
+ * }
+ *
+ *
+ * The configuration below is the same as the previous configuration.
+ *
+ *
+ * @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());
+ * }
+ * }
+ *
+ *
+ * The configuration below is also the same as the above configuration.
+ *
+ *
+ * @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());
+ * }
+ * }
+ *
+ *
+ * @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 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,
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java
index 1f38253d40..77c840d5a0 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -23,6 +23,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -30,6 +31,8 @@ import org.springframework.security.web.header.HeaderWriter;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.header.writers.*;
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
+import org.springframework.security.web.header.writers.XContentTypeOptionsHeaderWriter;
+import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -121,6 +124,26 @@ public class HeadersConfigurer> extends
return contentTypeOptions.enable();
}
+ /**
+ * Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the X-Content-Type-Options:
+ *
+ *
+ * X-Content-Type-Options: nosniff
+ *
+ *
+ * @param contentTypeOptionsCustomizer the {@link Customizer} to provide more options for
+ * the {@link ContentTypeOptionsConfig}
+ * @return the {@link HeadersConfigurer} for additional customizations
+ * @throws Exception
+ */
+ public HeadersConfigurer contentTypeOptions(Customizer contentTypeOptionsCustomizer)
+ throws Exception {
+ contentTypeOptionsCustomizer.customize(contentTypeOptions.enable());
+ return HeadersConfigurer.this;
+ }
+
public final class ContentTypeOptionsConfig {
private XContentTypeOptionsHeaderWriter writer;
@@ -174,6 +197,25 @@ public class HeadersConfigurer> extends
return xssProtection.enable();
}
+ /**
+ * Note this is not comprehensive XSS protection!
+ *
+ *
+ * Allows customizing the {@link XXssProtectionHeaderWriter} which adds the X-XSS-Protection header
+ *
+ *
+ * @param xssCustomizer the {@link Customizer} to provide more options for
+ * the {@link XXssConfig}
+ * @return the {@link HeadersConfigurer} for additional customizations
+ * @throws Exception
+ */
+ public HeadersConfigurer xssProtection(Customizer xssCustomizer) throws Exception {
+ xssCustomizer.customize(xssProtection.enable());
+ return HeadersConfigurer.this;
+ }
+
public final class XXssConfig {
private XXssProtectionHeaderWriter writer;
@@ -268,6 +310,26 @@ public class HeadersConfigurer> extends
return cacheControl.enable();
}
+ /**
+ * Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
+ * following headers:
+ *
+ * - Cache-Control: no-cache, no-store, max-age=0, must-revalidate
+ * - Pragma: no-cache
+ * - Expires: 0
+ *
+ *
+ * @param cacheControlCustomizer the {@link Customizer} to provide more options for
+ * the {@link CacheControlConfig}
+ * @return the {@link HeadersConfigurer} for additional customizations
+ * @throws Exception
+ */
+ public HeadersConfigurer cacheControl(Customizer cacheControlCustomizer) throws Exception {
+ cacheControlCustomizer.customize(cacheControl.enable());
+ return HeadersConfigurer.this;
+ }
+
+
public final class CacheControlConfig {
private CacheControlHeadersWriter writer;
@@ -319,6 +381,21 @@ public class HeadersConfigurer> extends
return hsts.enable();
}
+ /**
+ * Allows customizing the {@link HstsHeaderWriter} which provides support for HTTP Strict Transport Security
+ * (HSTS).
+ *
+ * @param hstsCustomizer the {@link Customizer} to provide more options for
+ * the {@link HstsConfig}
+ * @return the {@link HeadersConfigurer} for additional customizations
+ * @throws Exception
+ */
+ public HeadersConfigurer httpStrictTransportSecurity(Customizer hstsCustomizer) throws Exception {
+ hstsCustomizer.customize(hsts.enable());
+ return HeadersConfigurer.this;
+ }
+
public final class HstsConfig {
private HstsHeaderWriter writer;
@@ -440,6 +517,19 @@ public class HeadersConfigurer> extends
return frameOptions.enable();
}
+ /**
+ * Allows customizing the {@link XFrameOptionsHeaderWriter}.
+ *
+ * @param frameOptionsCustomizer the {@link Customizer} to provide more options for
+ * the {@link FrameOptionsConfig}
+ * @return the {@link HeadersConfigurer} for additional customizations
+ * @throws Exception
+ */
+ public HeadersConfigurer frameOptions(Customizer frameOptionsCustomizer) throws Exception {
+ frameOptionsCustomizer.customize(frameOptions.enable());
+ return HeadersConfigurer.this;
+ }
+
public final class FrameOptionsConfig {
private XFrameOptionsHeaderWriter writer;
@@ -516,6 +606,20 @@ public class HeadersConfigurer> extends
return hpkp.enable();
}
+ /**
+ * Allows customizing the {@link HpkpHeaderWriter} which provides support for HTTP Public Key Pinning (HPKP).
+ *
+ * @param hpkpCustomizer the {@link Customizer} to provide more options for
+ * the {@link HpkpConfig}
+ * @return the {@link HeadersConfigurer} for additional customizations
+ * @throws Exception
+ */
+ public HeadersConfigurer httpPublicKeyPinning(Customizer hpkpCustomizer) throws Exception {
+ hpkpCustomizer.customize(hpkp.enable());
+ return HeadersConfigurer.this;
+ }
+
public final class HpkpConfig {
private HpkpHeaderWriter writer;
@@ -713,12 +817,57 @@ public class HeadersConfigurer> extends
return contentSecurityPolicy;
}
+ /**
+ *
+ * Allows configuration for Content Security Policy (CSP) Level 2.
+ *
+ *
+ *
+ * Calling this method automatically enables (includes) the Content-Security-Policy header in the response
+ * using the supplied security policy directive(s).
+ *
+ *
+ *
+ * Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which supports the writing
+ * of the two headers as detailed in the W3C Candidate Recommendation:
+ *
+ *
+ * - Content-Security-Policy
+ * - Content-Security-Policy-Report-Only
+ *
+ *
+ * @see ContentSecurityPolicyHeaderWriter
+ * @param contentSecurityCustomizer the {@link Customizer} to provide more options for
+ * the {@link ContentSecurityPolicyConfig}
+ * @return the {@link HeadersConfigurer} for additional customizations
+ * @throws Exception
+ */
+ public HeadersConfigurer contentSecurityPolicy(Customizer contentSecurityCustomizer)
+ throws Exception {
+ this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter();
+ contentSecurityCustomizer.customize(this.contentSecurityPolicy);
+
+ return HeadersConfigurer.this;
+ }
+
public final class ContentSecurityPolicyConfig {
private ContentSecurityPolicyHeaderWriter writer;
private ContentSecurityPolicyConfig() {
}
+ /**
+ * Sets the security policy directive(s) to be used in the response header.
+ *
+ * @param policyDirectives the security policy directive(s)
+ * @return the {@link ContentSecurityPolicyConfig} for additional configuration
+ * @throws IllegalArgumentException if policyDirectives is null or empty
+ */
+ public ContentSecurityPolicyConfig policyDirectives(String policyDirectives) {
+ this.writer.setPolicyDirectives(policyDirectives);
+ return this;
+ }
+
/**
* Enables (includes) the Content-Security-Policy-Report-Only header in the response.
*
@@ -860,6 +1009,31 @@ public class HeadersConfigurer> extends
return this.referrerPolicy;
}
+ /**
+ *
+ * Allows configuration for Referrer Policy.
+ *
+ *
+ *
+ * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
+ * of the header as detailed in the W3C Technical Report:
+ *
+ *
+ *
+ * @see ReferrerPolicyHeaderWriter
+ * @param referrerPolicyCustomizer the {@link Customizer} to provide more options for
+ * the {@link ReferrerPolicyConfig}
+ * @return the {@link HeadersConfigurer} for additional customizations
+ * @throws Exception
+ */
+ public HeadersConfigurer referrerPolicy(Customizer referrerPolicyCustomizer) throws Exception {
+ this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter();
+ referrerPolicyCustomizer.customize(this.referrerPolicy);
+ return HeadersConfigurer.this;
+ }
+
public final class ReferrerPolicyConfig {
private ReferrerPolicyHeaderWriter writer;
@@ -867,6 +1041,18 @@ public class HeadersConfigurer> extends
private ReferrerPolicyConfig() {
}
+ /**
+ * Sets the policy to be used in the response header.
+ *
+ * @param policy a referrer policy
+ * @return the {@link ReferrerPolicyConfig} for additional configuration
+ * @throws IllegalArgumentException if policy is null
+ */
+ public ReferrerPolicyConfig policy(ReferrerPolicy policy) {
+ this.writer.setPolicy(policy);
+ return this;
+ }
+
public HeadersConfigurer and() {
return HeadersConfigurer.this;
}
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java
index cb7c220558..ad8f4e033a 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java
@@ -26,6 +26,7 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.event.GenericApplicationListenerAdapter;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
@@ -249,6 +250,19 @@ public final class SessionManagementConfigurer>
return new SessionFixationConfigurer();
}
+ /**
+ * Allows configuring session fixation protection.
+ *
+ * @param sessionFixationCustomizer the {@link Customizer} to provide more options for
+ * the {@link SessionFixationConfigurer}
+ * @return the {@link SessionManagementConfigurer} for further customizations
+ */
+ public SessionManagementConfigurer sessionFixation(Customizer sessionFixationCustomizer)
+ throws Exception {
+ sessionFixationCustomizer.customize(new SessionFixationConfigurer());
+ return this;
+ }
+
/**
* Controls the maximum number of sessions for a user. The default is to allow any
* number of users.
@@ -260,6 +274,20 @@ public final class SessionManagementConfigurer>
return new ConcurrencyControlConfigurer();
}
+ /**
+ * Controls the maximum number of sessions for a user. The default is to allow any
+ * number of users.
+ *
+ * @param sessionConcurrencyCustomizer the {@link Customizer} to provide more options for
+ * the {@link ConcurrencyControlConfigurer}
+ * @return the {@link SessionManagementConfigurer} for further customizations
+ */
+ public SessionManagementConfigurer sessionConcurrency(Customizer sessionConcurrencyCustomizer)
+ throws Exception {
+ sessionConcurrencyCustomizer.customize(new ConcurrencyControlConfigurer());
+ return this;
+ }
+
/**
* Invokes {@link #postProcess(Object)} and sets the
* {@link SessionAuthenticationStrategy} for session fixation.
@@ -338,6 +366,18 @@ public final class SessionManagementConfigurer>
*/
public final class ConcurrencyControlConfigurer {
+ /**
+ * Controls the maximum number of sessions for a user. The default is to allow any
+ * number of users.
+ *
+ * @param maximumSessions the maximum number of sessions for a user
+ * @return the {@link ConcurrencyControlConfigurer} for further customizations
+ */
+ public ConcurrencyControlConfigurer maximumSessions(int maximumSessions) {
+ SessionManagementConfigurer.this.maximumSessions = maximumSessions;
+ return this;
+ }
+
/**
* The URL to redirect to if a user tries to access a resource and their session
* has been expired due to too many sessions for the current user. The default is
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java
index f4a5c2c366..066ca0c692 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -16,6 +16,7 @@
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
@@ -135,6 +136,20 @@ public final class OAuth2ClientConfigurer> exte
return this.authorizationCodeGrantConfigurer;
}
+ /**
+ * Configures the OAuth 2.0 Authorization Code Grant.
+ *
+ * @param authorizationCodeGrantCustomizer the {@link Customizer} to provide more options for
+ * the {@link AuthorizationCodeGrantConfigurer}
+ * @return the {@link OAuth2ClientConfigurer} for further customizations
+ * @throws Exception
+ */
+ public OAuth2ClientConfigurer authorizationCodeGrant(Customizer authorizationCodeGrantCustomizer)
+ throws Exception {
+ authorizationCodeGrantCustomizer.customize(this.authorizationCodeGrantConfigurer);
+ return this;
+ }
+
/**
* Configuration options for the OAuth 2.0 Authorization Code Grant.
*/
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java
index 5e0bb87a2f..b54b522591 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java
@@ -20,6 +20,7 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
@@ -201,6 +202,20 @@ public final class OAuth2LoginConfigurer> exten
return this.authorizationEndpointConfig;
}
+ /**
+ * Configures the Authorization Server's Authorization Endpoint.
+ *
+ * @param authorizationEndpointCustomizer the {@link Customizer} to provide more options for
+ * the {@link AuthorizationEndpointConfig}
+ * @return the {@link OAuth2LoginConfigurer} for further customizations
+ * @throws Exception
+ */
+ public OAuth2LoginConfigurer authorizationEndpoint(Customizer authorizationEndpointCustomizer)
+ throws Exception {
+ authorizationEndpointCustomizer.customize(this.authorizationEndpointConfig);
+ return this;
+ }
+
/**
* Configuration options for the Authorization Server's Authorization Endpoint.
*/
@@ -268,6 +283,20 @@ public final class OAuth2LoginConfigurer> exten
return this.tokenEndpointConfig;
}
+ /**
+ * Configures the Authorization Server's Token Endpoint.
+ *
+ * @param tokenEndpointCustomizer the {@link Customizer} to provide more options for
+ * the {@link TokenEndpointConfig}
+ * @return the {@link OAuth2LoginConfigurer} for further customizations
+ * @throws Exception
+ */
+ public OAuth2LoginConfigurer tokenEndpoint(Customizer tokenEndpointCustomizer)
+ throws Exception {
+ tokenEndpointCustomizer.customize(this.tokenEndpointConfig);
+ return this;
+ }
+
/**
* Configuration options for the Authorization Server's Token Endpoint.
*/
@@ -310,6 +339,20 @@ public final class OAuth2LoginConfigurer> exten
return this.redirectionEndpointConfig;
}
+ /**
+ * Configures the Client's Redirection Endpoint.
+ *
+ * @param redirectionEndpointCustomizer the {@link Customizer} to provide more options for
+ * the {@link RedirectionEndpointConfig}
+ * @return the {@link OAuth2LoginConfigurer} for further customizations
+ * @throws Exception
+ */
+ public OAuth2LoginConfigurer redirectionEndpoint(Customizer redirectionEndpointCustomizer)
+ throws Exception {
+ redirectionEndpointCustomizer.customize(this.redirectionEndpointConfig);
+ return this;
+ }
+
/**
* Configuration options for the Client's Redirection Endpoint.
*/
@@ -350,6 +393,20 @@ public final class OAuth2LoginConfigurer> exten
return this.userInfoEndpointConfig;
}
+ /**
+ * Configures the Authorization Server's UserInfo Endpoint.
+ *
+ * @param userInfoEndpointCustomizer the {@link Customizer} to provide more options for
+ * the {@link UserInfoEndpointConfig}
+ * @return the {@link OAuth2LoginConfigurer} for further customizations
+ * @throws Exception
+ */
+ public OAuth2LoginConfigurer userInfoEndpoint(Customizer userInfoEndpointCustomizer)
+ throws Exception {
+ userInfoEndpointCustomizer.customize(this.userInfoEndpointConfig);
+ return this;
+ }
+
/**
* Configuration options for the Authorization Server's UserInfo Endpoint.
*/
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java
index 2d4ffb0cbd..589dd391e5 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java
@@ -25,6 +25,7 @@ import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationManagerResolver;
import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
@@ -65,11 +66,12 @@ import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSe
* {@link #accessDeniedHandler(AccessDeniedHandler)} - customizes how access denied errors are handled
* {@link #authenticationEntryPoint(AuthenticationEntryPoint)} - customizes how authentication failures are handled
* {@link #bearerTokenResolver(BearerTokenResolver)} - customizes how to resolve a bearer token from the request
- * {@link #jwt()} - enables Jwt-encoded bearer token support
+ * {@link #jwt(Customizer)} - enables Jwt-encoded bearer token support
+ * {@link #opaqueToken(Customizer)} - enables opaque bearer token support
*
*
*
- * When using {@link #jwt()}, either
+ * When using {@link #jwt(Customizer)}, either
*
*
* -
@@ -83,7 +85,7 @@ import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSe
*
*
*
- * Also with {@link #jwt()} consider
+ * Also with {@link #jwt(Customizer)} consider
*
*
* -
@@ -93,12 +95,12 @@ import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSe
*
*
*
- * When using {@link #opaque()}, supply an introspection endpoint and its authentication configuration
+ * When using {@link #opaqueToken(Customizer)}, supply an introspection endpoint and its authentication configuration
*
*
* Security Filters
*
- * The following {@code Filter}s are populated when {@link #jwt()} is configured:
+ * The following {@code Filter}s are populated when {@link #jwt(Customizer)} is configured:
*
*
* - {@link BearerTokenAuthenticationFilter}
@@ -180,6 +182,22 @@ public final class OAuth2ResourceServerConfigurer jwt(Customizer jwtCustomizer) throws Exception {
+ if ( this.jwtConfigurer == null ) {
+ this.jwtConfigurer = new JwtConfigurer(this.context);
+ }
+ jwtCustomizer.customize(this.jwtConfigurer);
+ return this;
+ }
+
public OpaqueTokenConfigurer opaqueToken() {
if (this.opaqueTokenConfigurer == null) {
this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context);
@@ -188,6 +206,23 @@ public final class OAuth2ResourceServerConfigurer opaqueToken(Customizer opaqueTokenCustomizer)
+ throws Exception {
+ if (this.opaqueTokenConfigurer == null) {
+ this.opaqueTokenConfigurer = new OpaqueTokenConfigurer(this.context);
+ }
+ opaqueTokenCustomizer.customize(this.opaqueTokenConfigurer);
+ return this;
+ }
+
@Override
public void init(H http) throws Exception {
registerDefaultAccessDeniedHandler(http);
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurer.java
index 6f7e362856..0ec0077de1 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * 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.
@@ -27,6 +27,7 @@ import org.openid4java.consumer.ConsumerManager;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@@ -148,6 +149,24 @@ public final class OpenIDLoginConfigurer> exten
return attributeExchangeConfigurer;
}
+ /**
+ * Sets up OpenID attribute exchange for OpenIDs matching the specified pattern.
+ * The default pattern is ".*", it can be specified using
+ * {@link AttributeExchangeConfigurer#identifierPattern(String)}
+ *
+ * @param attributeExchangeCustomizer the {@link Customizer} to provide more options for
+ * the {@link AttributeExchangeConfigurer}
+ * @return a {@link OpenIDLoginConfigurer} for further customizations
+ * @throws Exception
+ */
+ public OpenIDLoginConfigurer attributeExchange(Customizer attributeExchangeCustomizer)
+ throws Exception {
+ AttributeExchangeConfigurer attributeExchangeConfigurer = new AttributeExchangeConfigurer(".*");
+ attributeExchangeCustomizer.customize(attributeExchangeConfigurer);
+ this.attributeExchangeConfigurers.add(attributeExchangeConfigurer);
+ return this;
+ }
+
/**
* Allows specifying the {@link OpenIDConsumer} to be used. The default is using an
* {@link OpenID4JavaConsumer}.
@@ -373,7 +392,7 @@ public final class OpenIDLoginConfigurer> exten
* @author Rob Winch
*/
public final class AttributeExchangeConfigurer {
- private final String identifier;
+ private String identifier;
private List attributes = new ArrayList<>();
private List attributeConfigurers = new ArrayList<>();
@@ -395,6 +414,19 @@ public final class OpenIDLoginConfigurer> exten
return OpenIDLoginConfigurer.this;
}
+ /**
+ * Sets the regular expression for matching on OpenID's (i.e.
+ * "https://www.google.com/.*", ".*yahoo.com.*", etc)
+ *
+ * @param identifierPattern the regular expression for matching on OpenID's
+ * @return the {@link AttributeExchangeConfigurer} for further customization of
+ * attribute exchange
+ */
+ public AttributeExchangeConfigurer identifierPattern(String identifierPattern) {
+ this.identifier = identifierPattern;
+ return this;
+ }
+
/**
* Adds an {@link OpenIDAttribute} to be obtained for the configured OpenID
* pattern.
@@ -419,6 +451,22 @@ public final class OpenIDLoginConfigurer> exten
return attributeConfigurer;
}
+ /**
+ * Adds an {@link OpenIDAttribute} named "default-attribute".
+ * The name can by updated using {@link AttributeConfigurer#name(String)}.
+ *
+ * @param attributeCustomizer the {@link Customizer} to provide more options for
+ * the {@link AttributeConfigurer}
+ * @return a {@link AttributeExchangeConfigurer} for further customizations
+ * @throws Exception
+ */
+ public AttributeExchangeConfigurer attribute(Customizer attributeCustomizer) throws Exception {
+ AttributeConfigurer attributeConfigurer = new AttributeConfigurer();
+ attributeCustomizer.customize(attributeConfigurer);
+ this.attributeConfigurers.add(attributeConfigurer);
+ return this;
+ }
+
/**
* Gets the {@link OpenIDAttribute}'s for the configured OpenID pattern
* @return
@@ -443,6 +491,16 @@ public final class OpenIDLoginConfigurer> exten
private boolean required = false;
private String type;
+ /**
+ * Creates a new instance named "default-attribute".
+ * The name can by updated using {@link #name(String)}.
+ *
+ * @see AttributeExchangeConfigurer#attribute(String)
+ */
+ private AttributeConfigurer() {
+ this.name = "default-attribute";
+ }
+
/**
* Creates a new instance
* @param name the name of the attribute
@@ -486,6 +544,16 @@ public final class OpenIDLoginConfigurer> exten
return this;
}
+ /**
+ * The OpenID attribute name.
+ * @param name
+ * @return the {@link AttributeConfigurer} for further customizations
+ */
+ public AttributeConfigurer name(String name) {
+ this.name = name;
+ return this;
+ }
+
/**
* Gets the {@link AttributeExchangeConfigurer} for further customization of
* the attributes
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java
index b10dcdbe59..11d80e02d8 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -18,18 +18,22 @@ package org.springframework.security.config.annotation.web.configurers;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @author Rob Winch
@@ -44,7 +48,7 @@ public class AnonymousConfigurerTests {
@Test
public void requestWhenAnonymousTwiceInvokedThenDoesNotOverride() throws Exception {
- this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
+ this.spring.register(InvokeTwiceDoesNotOverride.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/"))
.andExpect(content().string("principal"));
@@ -63,13 +67,99 @@ public class AnonymousConfigurerTests {
.and()
.anonymous();
}
+ }
+
+ @Test
+ public void requestWhenAnonymousPrincipalInLambdaThenPrincipalUsed() throws Exception {
+ this.spring.register(AnonymousPrincipalInLambdaConfig.class, PrincipalController.class).autowire();
+
+ this.mockMvc.perform(get("/"))
+ .andExpect(content().string("principal"));
+ }
+
+ @EnableWebSecurity
+ @EnableWebMvc
+ static class AnonymousPrincipalInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .anonymous(anonymous ->
+ anonymous
+ .principal("principal")
+ );
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenAnonymousDisabledInLambdaThenRespondsWithForbidden() throws Exception {
+ this.spring.register(AnonymousDisabledInLambdaConfig.class, PrincipalController.class).autowire();
+
+ this.mockMvc.perform(get("/"))
+ .andExpect(status().isForbidden());
+ }
+
+ @EnableWebSecurity
+ static class AnonymousDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().permitAll()
+ )
+ .anonymous(AbstractHttpConfigurer::disable);
+ // @formatter:on
+ }
+
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenAnonymousWithDefaultsInLambdaThenRespondsWithOk() throws Exception {
+ this.spring.register(AnonymousWithDefaultsInLambdaConfig.class, PrincipalController.class).autowire();
+
+ this.mockMvc.perform(get("/"))
+ .andExpect(status().isOk());
+ }
+
+ @EnableWebSecurity
+ static class AnonymousWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().permitAll()
+ )
+ .anonymous(withDefaults());
+ // @formatter:on
+ }
+
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
- @RestController
- static class PrincipalController {
- @GetMapping("/")
- String principal(@AuthenticationPrincipal String principal) {
- return principal;
- }
+ @RestController
+ static class PrincipalController {
+ @GetMapping("/")
+ String principal(@AuthenticationPrincipal String principal) {
+ return principal;
}
}
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java
index 526f3b8657..b9fb86db21 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * 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.
@@ -49,6 +49,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy;
+import static org.springframework.security.config.Customizer.withDefaults;
/**
* @author Rob Winch
@@ -113,6 +114,39 @@ public class AuthorizeRequestsTests {
}
}
+ @Test
+ public void postWhenPostDenyAllInLambdaThenRespondsWithForbidden() throws Exception {
+ loadConfig(AntMatchersNoPatternsInLambdaConfig.class);
+ this.request.setMethod("POST");
+
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
+ }
+
+ @EnableWebSecurity
+ @Configuration
+ static class AntMatchersNoPatternsInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers(HttpMethod.POST).denyAll()
+ );
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication();
+ // @formatter:on
+ }
+ }
+
// SEC-2256
@Test
public void antMatchersPathVariables() throws Exception {
@@ -314,6 +348,66 @@ public class AuthorizeRequestsTests {
}
}
+ @Test
+ public void requestWhenMvcMatcherDenyAllThenRespondsWithUnauthorized() throws Exception {
+ loadConfig(MvcMatcherInLambdaConfig.class);
+
+ this.request.setRequestURI("/path");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+ setup();
+
+ this.request.setRequestURI("/path.html");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+ setup();
+
+ this.request.setServletPath("/path/");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @EnableWebSecurity
+ @Configuration
+ @EnableWebMvc
+ static class MvcMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .httpBasic(withDefaults())
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .mvcMatchers("/path").denyAll()
+ );
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication();
+ // @formatter:on
+ }
+
+ @RestController
+ static class PathController {
+ @RequestMapping("/path")
+ public String path() {
+ return "path";
+ }
+ }
+ }
+
@Test
public void mvcMatcherServletPath() throws Exception {
loadConfig(MvcMatcherServletPathConfig.class);
@@ -391,6 +485,85 @@ public class AuthorizeRequestsTests {
}
}
+ @Test
+ public void requestWhenMvcMatcherServletPathDenyAllThenMatchesOnServletPath() throws Exception {
+ loadConfig(MvcMatcherServletPathInLambdaConfig.class);
+
+ this.request.setServletPath("/spring");
+ this.request.setRequestURI("/spring/path");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+ setup();
+
+ this.request.setServletPath("/spring");
+ this.request.setRequestURI("/spring/path.html");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+ setup();
+
+ this.request.setServletPath("/spring");
+ this.request.setRequestURI("/spring/path/");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+ setup();
+
+ this.request.setServletPath("/foo");
+ this.request.setRequestURI("/foo/path");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+ setup();
+
+ this.request.setServletPath("/");
+ this.request.setRequestURI("/path");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+ }
+
+ @EnableWebSecurity
+ @Configuration
+ @EnableWebMvc
+ static class MvcMatcherServletPathInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .httpBasic(withDefaults())
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .mvcMatchers("/path").servletPath("/spring").denyAll()
+ );
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication();
+ // @formatter:on
+ }
+
+ @RestController
+ static class PathController {
+ @RequestMapping("/path")
+ public String path() {
+ return "path";
+ }
+ }
+ }
+
@Test
public void mvcMatcherPathVariables() throws Exception {
loadConfig(MvcMatcherPathVariablesConfig.class);
@@ -441,6 +614,58 @@ public class AuthorizeRequestsTests {
}
}
+ @Test
+ public void requestWhenMvcMatcherPathVariablesThenMatchesOnPathVariables() throws Exception {
+ loadConfig(MvcMatcherPathVariablesInLambdaConfig.class);
+
+ this.request.setRequestURI("/user/user");
+
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+ this.setup();
+ this.request.setRequestURI("/user/deny");
+
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @EnableWebSecurity
+ @Configuration
+ @EnableWebMvc
+ static class MvcMatcherPathVariablesInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .httpBasic(withDefaults())
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .mvcMatchers("/user/{userName}").access("#userName == 'user'")
+ );
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication();
+ // @formatter:on
+ }
+
+ @RestController
+ static class PathController {
+ @RequestMapping("/path")
+ public String path() {
+ return "path";
+ }
+ }
+ }
+
@EnableWebSecurity
@Configuration
@EnableWebMvc
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java
index c755c5f3a3..c33682e716 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ChannelSecurityConfigurerTests.java
@@ -135,4 +135,27 @@ public class ChannelSecurityConfigurerTests {
// @formatter:on
}
}
+
+ @Test
+ public void requestWhenRequiresChannelConfiguredInLambdaThenRedirectsToHttps() throws Exception {
+ this.spring.register(RequiresChannelInLambdaConfig.class).autowire();
+
+ mvc.perform(get("/"))
+ .andExpect(redirectedUrl("https://localhost/"));
+ }
+
+ @EnableWebSecurity
+ static class RequiresChannelInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .requiresChannel(requiresChannel ->
+ requiresChannel
+ .anyRequest().requiresSecure()
+ );
+ // @formatter:on
+ }
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
index 8122817caf..b880b3ef5b 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CorsConfigurerTests.java
@@ -42,6 +42,7 @@ import java.util.Arrays;
import java.util.Collections;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@@ -131,6 +132,56 @@ public class CorsConfigurerTests {
}
}
+ @Test
+ public void getWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
+ this.spring.register(MvcCorsInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/")
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @Test
+ public void optionsWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
+ this.spring.register(MvcCorsInLambdaConfig.class).autowire();
+
+ this.mvc.perform(options("/")
+ .header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @EnableWebMvc
+ @EnableWebSecurity
+ static class MvcCorsInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .cors(withDefaults());
+ // @formatter:on
+ }
+
+ @RestController
+ @CrossOrigin(methods = {
+ RequestMethod.GET, RequestMethod.POST
+ })
+ static class CorsController {
+ @RequestMapping("/")
+ String hello() {
+ return "Hello";
+ }
+ }
+ }
+
@Test
public void getWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(ConfigSourceConfig.class).autowire();
@@ -180,6 +231,58 @@ public class CorsConfigurerTests {
}
}
+ @Test
+ public void getWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
+ throws Exception {
+ this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/")
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @Test
+ public void optionsWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
+ throws Exception {
+ this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
+
+ this.mvc.perform(options("/")
+ .header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @EnableWebSecurity
+ static class ConfigSourceInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .cors(withDefaults());
+ // @formatter:on
+ }
+
+ @Bean
+ CorsConfigurationSource corsConfigurationSource() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
+ corsConfiguration.setAllowedMethods(Arrays.asList(
+ RequestMethod.GET.name(),
+ RequestMethod.POST.name()));
+ source.registerCorsConfiguration("/**", corsConfiguration);
+ return source;
+ }
+ }
+
@Test
public void getWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterConfig.class).autowire();
@@ -228,4 +331,54 @@ public class CorsConfigurerTests {
return new CorsFilter(source);
}
}
+
+ @Test
+ public void getWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
+ this.spring.register(CorsFilterInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/")
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @Test
+ public void optionsWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
+ this.spring.register(CorsFilterInLambdaConfig.class).autowire();
+
+ this.mvc.perform(options("/")
+ .header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
+ .header(HttpHeaders.ORIGIN, "https://example.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().exists("Access-Control-Allow-Origin"))
+ .andExpect(header().exists("X-Content-Type-Options"));
+ }
+
+ @EnableWebSecurity
+ static class CorsFilterInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .cors(withDefaults());
+ // @formatter:on
+ }
+
+ @Bean
+ CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
+ corsConfiguration.setAllowedMethods(Arrays.asList(
+ RequestMethod.GET.name(),
+ RequestMethod.POST.name()));
+ source.registerCorsConfiguration("/**", corsConfiguration);
+ return new CorsFilter(source);
+ }
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java
index 39af9745cb..56d99f0610 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerIgnoringRequestMatchersTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -75,6 +75,36 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
}
}
+ @Test
+ public void requestWhenIgnoringRequestMatchersInLambdaThenAugmentedByConfiguredRequestMatcher()
+ throws Exception {
+ this.spring.register(IgnoringRequestInLambdaMatchers.class, BasicController.class).autowire();
+
+ this.mvc.perform(get("/path"))
+ .andExpect(status().isForbidden());
+
+ this.mvc.perform(post("/path"))
+ .andExpect(status().isOk());
+ }
+
+ @EnableWebSecurity
+ static class IgnoringRequestInLambdaMatchers extends WebSecurityConfigurerAdapter {
+ RequestMatcher requestMatcher =
+ request -> HttpMethod.POST.name().equals(request.getMethod());
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .csrf(csrf ->
+ csrf
+ .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
+ .ignoringRequestMatchers(this.requestMatcher)
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void requestWhenIgnoringRequestMatcherThenUnionsWithConfiguredIgnoringAntMatchers()
throws Exception {
@@ -107,6 +137,40 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
}
}
+ @Test
+ public void requestWhenIgnoringRequestMatcherInLambdaThenUnionsWithConfiguredIgnoringAntMatchers()
+ throws Exception {
+
+ this.spring.register(IgnoringPathsAndMatchersInLambdaConfig.class, BasicController.class).autowire();
+
+ this.mvc.perform(put("/csrf"))
+ .andExpect(status().isForbidden());
+
+ this.mvc.perform(post("/csrf"))
+ .andExpect(status().isOk());
+
+ this.mvc.perform(put("/no-csrf"))
+ .andExpect(status().isOk());
+ }
+
+ @EnableWebSecurity
+ static class IgnoringPathsAndMatchersInLambdaConfig extends WebSecurityConfigurerAdapter {
+ RequestMatcher requestMatcher =
+ request -> HttpMethod.POST.name().equals(request.getMethod());
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .csrf(csrf ->
+ csrf
+ .ignoringAntMatchers("/no-csrf")
+ .ignoringRequestMatchers(this.requestMatcher)
+ );
+ // @formatter:on
+ }
+ }
+
@RestController
public static class BasicController {
@RequestMapping("/path")
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java
index e66fd1a075..22e88597ce 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/CsrfConfigurerTests.java
@@ -55,6 +55,7 @@ import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -210,6 +211,26 @@ public class CsrfConfigurerTests {
}
}
+ @Test
+ public void postWhenCsrfDisabledInLambdaThenRespondsWithOk() throws Exception {
+ this.spring.register(DisableCsrfInLambdaConfig.class, BasicController.class).autowire();
+
+ this.mvc.perform(post("/"))
+ .andExpect(status().isOk());
+ }
+
+ @EnableWebSecurity
+ static class DisableCsrfInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .csrf(AbstractHttpConfigurer::disable);
+ // @formatter:on
+ }
+ }
+
// SEC-2498
@Test
public void loginWhenCsrfDisabledThenRedirectsToPreviousPostRequest() throws Exception {
@@ -386,6 +407,40 @@ public class CsrfConfigurerTests {
}
}
+ @Test
+ public void requireCsrfProtectionMatcherInLambdaWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
+ RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
+ this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
+ when(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any()))
+ .thenReturn(false);
+
+ this.mvc.perform(get("/"))
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ public void requireCsrfProtectionMatcherInLambdaWhenRequestMatchesThenRespondsWithForbidden() throws Exception {
+ RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
+ when(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any())).thenReturn(true);
+ this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
+
+ this.mvc.perform(get("/"))
+ .andExpect(status().isForbidden());
+ }
+
+ @EnableWebSecurity
+ static class RequireCsrfProtectionMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
+ static RequestMatcher MATCHER;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .csrf(csrf -> csrf.requireCsrfProtectionMatcher(MATCHER));
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenCustomCsrfTokenRepositoryThenRepositoryIsUsed() throws Exception {
CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
@@ -454,6 +509,32 @@ public class CsrfConfigurerTests {
}
}
+ @Test
+ public void getWhenCustomCsrfTokenRepositoryInLambdaThenRepositoryIsUsed() throws Exception {
+ CsrfTokenRepositoryInLambdaConfig.REPO = mock(CsrfTokenRepository.class);
+ when(CsrfTokenRepositoryInLambdaConfig.REPO.loadToken(any()))
+ .thenReturn(new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"));
+ this.spring.register(CsrfTokenRepositoryInLambdaConfig.class, BasicController.class).autowire();
+
+ this.mvc.perform(get("/"))
+ .andExpect(status().isOk());
+ verify(CsrfTokenRepositoryInLambdaConfig.REPO).loadToken(any(HttpServletRequest.class));
+ }
+
+ @EnableWebSecurity
+ static class CsrfTokenRepositoryInLambdaConfig extends WebSecurityConfigurerAdapter {
+ static CsrfTokenRepository REPO;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .formLogin(withDefaults())
+ .csrf(csrf -> csrf.csrfTokenRepository(REPO));
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenCustomAccessDeniedHandlerThenHandlerIsUsed() throws Exception {
AccessDeniedHandlerConfig.DENIED_HANDLER = mock(AccessDeniedHandler.class);
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java
index aad85a825b..ef1084cdbd 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurerAccessDeniedHandlerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -86,6 +86,48 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
}
}
+ @Test
+ @WithMockUser(roles = "ANYTHING")
+ public void getWhenAccessDeniedOverriddenInLambdaThenCustomizesResponseByRequest()
+ throws Exception {
+ this.spring.register(RequestMatcherBasedAccessDeniedHandlerInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/hello"))
+ .andExpect(status().isIAmATeapot());
+
+ this.mvc.perform(get("/goodbye"))
+ .andExpect(status().isForbidden());
+ }
+
+ @EnableWebSecurity
+ static class RequestMatcherBasedAccessDeniedHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
+ AccessDeniedHandler teapotDeniedHandler =
+ (request, response, exception) ->
+ response.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().denyAll()
+ )
+ .exceptionHandling(exceptionHandling ->
+ exceptionHandling
+ .defaultAccessDeniedHandlerFor(
+ this.teapotDeniedHandler,
+ new AntPathRequestMatcher("/hello/**")
+ )
+ .defaultAccessDeniedHandlerFor(
+ new AccessDeniedHandlerImpl(),
+ AnyRequestMatcher.INSTANCE
+ )
+ );
+ // @formatter:on
+ }
+ }
+
@Test
@WithMockUser(roles = "ANYTHING")
public void getWhenAccessDeniedOverriddenByOnlyOneHandlerThenAllRequestsUseThatHandler()
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java
index 4211806094..f7b9c1635e 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/FormLoginConfigurerTests.java
@@ -42,6 +42,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.logout;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -195,6 +196,82 @@ public class FormLoginConfigurerTests {
}
}
+ @Test
+ public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
+ this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(formLogin().user("username", "user").password("password", "password"))
+ .andExpect(status().isFound())
+ .andExpect(redirectedUrl("/"));
+ }
+
+ @Test
+ public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultFailureUrl() throws Exception {
+ this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(formLogin().user("invalid"))
+ .andExpect(status().isFound())
+ .andExpect(redirectedUrl("/login?error"));
+ }
+
+ @Test
+ public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultSuccessUrl() throws Exception {
+ this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(formLogin())
+ .andExpect(status().isFound())
+ .andExpect(redirectedUrl("/"));
+ }
+
+ @Test
+ public void getLoginPageWhenFormLoginDefaultsInLambdaThenNotSecured() throws Exception {
+ this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(get("/login"))
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ public void loginWhenFormLoginDefaultsInLambdaThenSecured() throws Exception {
+ this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(post("/login"))
+ .andExpect(status().isForbidden());
+ }
+
+ @Test
+ public void requestProtectedWhenFormLoginDefaultsInLambdaThenRedirectsToLogin() throws Exception {
+ this.spring.register(FormLoginInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(get("/private"))
+ .andExpect(status().isFound())
+ .andExpect(redirectedUrl("http://localhost/login"));
+ }
+
+ @EnableWebSecurity
+ static class FormLoginInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
+ .formLogin(withDefaults());
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
@Test
public void getLoginPageWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
@@ -297,6 +374,34 @@ public class FormLoginConfigurerTests {
}
}
+ @Test
+ public void getLoginPageWhenCustomLoginPageInLambdaThenPermittedAndNoRedirect() throws Exception {
+ this.spring.register(FormLoginDefaultsInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(get("/authenticate"))
+ .andExpect(redirectedUrl(null));
+ }
+
+ @EnableWebSecurity
+ static class FormLoginDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
+ .formLogin(formLogin ->
+ formLogin
+ .loginPage("/authenticate")
+ .permitAll()
+ )
+ .logout(LogoutConfigurer::permitAll);
+ // @formatter:on
+ }
+ }
+
@Test
public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlConfig.class).autowire();
@@ -340,6 +445,51 @@ public class FormLoginConfigurerTests {
}
}
+ @Test
+ public void loginWhenCustomLoginProcessingUrlInLambdaThenRedirectsToHome() throws Exception {
+ this.spring.register(FormLoginLoginProcessingUrlInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(formLogin("/loginCheck"))
+ .andExpect(status().isFound())
+ .andExpect(redirectedUrl("/"));
+ }
+
+ @EnableWebSecurity
+ static class FormLoginLoginProcessingUrlInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .formLogin(formLogin ->
+ formLogin
+ .loginProcessingUrl("/loginCheck")
+ .loginPage("/login")
+ .defaultSuccessUrl("/", true)
+ .permitAll()
+ )
+ .logout(logout ->
+ logout
+ .logoutSuccessUrl("/login")
+ .logoutUrl("/logout")
+ .deleteCookies("JSESSIONID")
+ );
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
@Test
public void requestWhenCustomPortMapperThenPortMapperUsed() throws Exception {
FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class);
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java
index f8ed9adcf2..0ca822a6fd 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.java
@@ -36,6 +36,7 @@ import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@@ -87,6 +88,36 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenHeadersConfiguredInLambdaThenDefaultHeadersInResponse() throws Exception {
+ this.spring.register(HeadersInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
+ .andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, XFrameOptionsMode.DENY.name()))
+ .andExpect(header().string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains"))
+ .andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
+ .andExpect(header().string(HttpHeaders.EXPIRES, "0"))
+ .andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
+ .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block"))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
+ HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
+ HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
+ }
+
+ @EnableWebSecurity
+ static class HeadersInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(withDefaults());
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenHeaderDefaultsDisabledAndContentTypeConfiguredThenOnlyContentTypeHeaderInResponse()
throws Exception {
@@ -112,6 +143,33 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenOnlyContentTypeConfiguredInLambdaThenOnlyContentTypeHeaderInResponse()
+ throws Exception {
+ this.spring.register(ContentTypeOptionsInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/"))
+ .andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_CONTENT_TYPE_OPTIONS);
+ }
+
+ @EnableWebSecurity
+ static class ContentTypeOptionsInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .contentTypeOptions(withDefaults())
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenHeaderDefaultsDisabledAndFrameOptionsConfiguredThenOnlyFrameOptionsHeaderInResponse()
throws Exception {
@@ -190,6 +248,36 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenOnlyCacheControlConfiguredInLambdaThenCacheControlAndExpiresAndPragmaHeadersInResponse()
+ throws Exception {
+ this.spring.register(CacheControlInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
+ .andExpect(header().string(HttpHeaders.EXPIRES, "0"))
+ .andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(HttpHeaders.CACHE_CONTROL,
+ HttpHeaders.EXPIRES, HttpHeaders.PRAGMA);
+ }
+
+ @EnableWebSecurity
+ static class CacheControlInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .cacheControl(withDefaults())
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredThenOnlyXssProtectionHeaderInResponse()
throws Exception {
@@ -215,6 +303,33 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenOnlyXssProtectionConfiguredInLambdaThenOnlyXssProtectionHeaderInResponse()
+ throws Exception {
+ this.spring.register(XssProtectionInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block"))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION);
+ }
+
+ @EnableWebSecurity
+ static class XssProtectionInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .xssProtection(withDefaults())
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenFrameOptionsSameOriginConfiguredThenFrameOptionsHeaderHasValueSameOrigin() throws Exception {
this.spring.register(HeadersCustomSameOriginConfig.class).autowire();
@@ -237,6 +352,31 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenFrameOptionsSameOriginConfiguredInLambdaThenFrameOptionsHeaderHasValueSameOrigin()
+ throws Exception {
+ this.spring.register(HeadersCustomSameOriginInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, XFrameOptionsMode.SAMEORIGIN.name()))
+ .andReturn();
+ }
+
+ @EnableWebSecurity
+ static class HeadersCustomSameOriginInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .frameOptions(frameOptionsConfig -> frameOptionsConfig.sameOrigin())
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenHeaderDefaultsDisabledAndPublicHpkpWithNoPinThenNoHeadersInResponse() throws Exception {
this.spring.register(HpkpConfigNoPins.class).autowire();
@@ -465,6 +605,38 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenHpkpWithReportUriInLambdaThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
+ throws Exception {
+ this.spring.register(HpkpWithReportUriInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
+ "max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
+ }
+
+ @EnableWebSecurity
+ static class HpkpWithReportUriInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .httpPublicKeyPinning(hpkp ->
+ hpkp
+ .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
+ .reportUri("https://example.net/pkp-report")
+ )
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenContentSecurityPolicyConfiguredThenContentSecurityPolicyHeaderInResponse() throws Exception {
this.spring.register(ContentSecurityPolicyDefaultConfig.class).autowire();
@@ -515,6 +687,38 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenContentSecurityPolicyWithReportOnlyInLambdaThenContentSecurityPolicyReportOnlyHeaderInResponse()
+ throws Exception {
+ this.spring.register(ContentSecurityPolicyReportOnlyInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
+ "default-src 'self'; script-src trustedscripts.example.com"))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
+ }
+
+ @EnableWebSecurity
+ static class ContentSecurityPolicyReportOnlyInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .contentSecurityPolicy(csp ->
+ csp
+ .policyDirectives("default-src 'self'; script-src trustedscripts.example.com")
+ .reportOnly()
+ )
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void configureWhenContentSecurityPolicyEmptyThenException() {
assertThatThrownBy(() -> this.spring.register(ContentSecurityPolicyInvalidConfig.class).autowire())
@@ -536,6 +740,58 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void configureWhenContentSecurityPolicyEmptyInLambdaThenException() {
+ assertThatThrownBy(() -> this.spring.register(ContentSecurityPolicyInvalidInLambdaConfig.class).autowire())
+ .isInstanceOf(BeanCreationException.class)
+ .hasRootCauseInstanceOf(IllegalArgumentException.class);
+ }
+
+ @EnableWebSecurity
+ static class ContentSecurityPolicyInvalidInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .contentSecurityPolicy(csp ->
+ csp.policyDirectives("")
+ )
+ );
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void configureWhenContentSecurityPolicyNoPolicyDirectivesInLambdaThenDefaultHeaderValue() throws Exception {
+ this.spring.register(ContentSecurityPolicyNoDirectivesInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY,
+ "default-src 'self'"))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
+ }
+
+ @EnableWebSecurity
+ static class ContentSecurityPolicyNoDirectivesInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .contentSecurityPolicy(withDefaults())
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenReferrerPolicyConfiguredThenReferrerPolicyHeaderInResponse() throws Exception {
this.spring.register(ReferrerPolicyDefaultConfig.class).autowire();
@@ -560,6 +816,32 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenReferrerPolicyInLambdaThenReferrerPolicyHeaderInResponse() throws Exception {
+ this.spring.register(ReferrerPolicyDefaultInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy()))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
+ }
+
+ @EnableWebSecurity
+ static class ReferrerPolicyDefaultInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .referrerPolicy()
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenReferrerPolicyConfiguredWithCustomValueThenReferrerPolicyHeaderWithCustomValueInResponse()
throws Exception {
@@ -585,6 +867,34 @@ public class HeadersConfigurerTests {
}
}
+ @Test
+ public void getWhenReferrerPolicyConfiguredWithCustomValueInLambdaThenCustomValueInResponse() throws Exception {
+ this.spring.register(ReferrerPolicyCustomInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy()))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
+ }
+
+ @EnableWebSecurity
+ static class ReferrerPolicyCustomInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .referrerPolicy(referrerPolicy ->
+ referrerPolicy.policy(ReferrerPolicy.SAME_ORIGIN)
+ )
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void getWhenFeaturePolicyConfiguredThenFeaturePolicyHeaderInResponse() throws Exception {
this.spring.register(FeaturePolicyConfig.class).autowire();
@@ -656,4 +966,32 @@ public class HeadersConfigurerTests {
// @formatter:on
}
}
+
+ @Test
+ public void getWhenHstsConfiguredWithPreloadInLambdaThenStrictTransportSecurityHeaderWithPreloadInResponse()
+ throws Exception {
+ this.spring.register(HstsWithPreloadInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
+ .andExpect(header().string(HttpHeaders.STRICT_TRANSPORT_SECURITY,
+ "max-age=31536000 ; includeSubDomains ; preload"))
+ .andReturn();
+ assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
+ }
+
+ @EnableWebSecurity
+ static class HstsWithPreloadInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .httpStrictTransportSecurity(hstsConfig -> hstsConfig.preload(true))
+ );
+ // @formatter:on
+ }
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java
index a6445aa35b..43d956b3e5 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java
@@ -107,9 +107,10 @@ public class HttpBasicConfigurerTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
.httpBasic(withDefaults());
// @formatter:on
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java
index c05f8064a6..ef4d4a2e42 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpSecurityRequestMatchersTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -38,6 +38,7 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.security.config.Customizer.withDefaults;
/**
* @author Rob Winch
@@ -195,6 +196,62 @@ public class HttpSecurityRequestMatchersTests {
}
}
+ @Test
+ public void requestMatchersWhenMvcMatcherInLambdaThenPathIsSecured() throws Exception {
+ loadConfig(RequestMatchersMvcMatcherInLambdaConfig.class);
+
+ this.request.setServletPath("/path");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+ setup();
+
+ this.request.setServletPath("/path.html");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+ setup();
+
+ this.request.setServletPath("/path/");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @EnableWebSecurity
+ @Configuration
+ @EnableWebMvc
+ static class RequestMatchersMvcMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .requestMatchers(requestMatchers ->
+ requestMatchers
+ .mvcMatchers("/path")
+ )
+ .httpBasic(withDefaults())
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().denyAll()
+ );
+ // @formatter:on
+ }
+
+ @RestController
+ static class PathController {
+ @RequestMapping("/path")
+ public String path() {
+ return "path";
+ }
+ }
+ }
+
@Test
public void requestMatchersMvcMatcherServletPath() throws Exception {
loadConfig(RequestMatchersMvcMatcherServeltPathConfig.class);
@@ -260,6 +317,66 @@ public class HttpSecurityRequestMatchersTests {
}
}
+ @Test
+ public void requestMatcherWhensMvcMatcherServletPathInLambdaThenPathIsSecured() throws Exception {
+ loadConfig(RequestMatchersMvcMatcherServletPathInLambdaConfig.class);
+
+ this.request.setServletPath("/spring");
+ this.request.setRequestURI("/spring/path");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus())
+ .isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
+
+ setup();
+
+ this.request.setServletPath("");
+ this.request.setRequestURI("/path");
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+
+ setup();
+
+ this.request.setServletPath("/other");
+ this.request.setRequestURI("/other/path");
+
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
+
+ assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
+ }
+
+ @EnableWebSecurity
+ @Configuration
+ @EnableWebMvc
+ static class RequestMatchersMvcMatcherServletPathInLambdaConfig
+ extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .requestMatchers(requestMatchers ->
+ requestMatchers
+ .mvcMatchers("/path").servletPath("/spring")
+ .mvcMatchers("/never-match")
+ )
+ .httpBasic(withDefaults())
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().denyAll()
+ );
+ // @formatter:on
+ }
+
+ @RestController
+ static class PathController {
+ @RequestMapping("/path")
+ public String path() {
+ return "path";
+ }
+ }
+ }
+
public void loadConfig(Class>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java
index fac4baf354..57de13f087 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/JeeConfigurerTests.java
@@ -25,6 +25,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
+import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
import org.springframework.test.web.servlet.MockMvc;
@@ -125,4 +128,115 @@ public class JeeConfigurerTests {
// @formatter:on
}
}
+
+ @Test
+ public void requestWhenJeeMappableRolesInLambdaThenAuthenticatedWithMappableRoles() throws Exception {
+ this.spring.register(JeeMappableRolesConfig.class).autowire();
+ Principal user = mock(Principal.class);
+ when(user.getName()).thenReturn("user");
+
+ this.mvc.perform(get("/")
+ .principal(user)
+ .with(request -> {
+ request.addUserRole("ROLE_ADMIN");
+ request.addUserRole("ROLE_USER");
+ return request;
+ }))
+ .andExpect(authenticated().withRoles("USER"));
+ }
+
+ @EnableWebSecurity
+ public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
+ .jee(jee ->
+ jee
+ .mappableRoles("USER")
+ );
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenJeeMappableAuthoritiesInLambdaThenAuthenticatedWithMappableAuthorities() throws Exception {
+ this.spring.register(JeeMappableAuthoritiesConfig.class).autowire();
+ Principal user = mock(Principal.class);
+ when(user.getName()).thenReturn("user");
+
+ this.mvc.perform(get("/")
+ .principal(user)
+ .with(request -> {
+ request.addUserRole("ROLE_ADMIN");
+ request.addUserRole("ROLE_USER");
+ return request;
+ }))
+ .andExpect(authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER")));
+ }
+
+ @EnableWebSecurity
+ public static class JeeMappableAuthoritiesConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
+ .jee(jee ->
+ jee
+ .mappableAuthorities("ROLE_USER")
+ );
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenCustomAuthenticatedUserDetailsServiceInLambdaThenCustomAuthenticatedUserDetailsServiceUsed()
+ throws Exception {
+ this.spring.register(JeeCustomAuthenticatedUserDetailsServiceConfig.class).autowire();
+ Principal user = mock(Principal.class);
+ User userDetails = new User("user", "N/A", true, true, true, true,
+ AuthorityUtils.createAuthorityList("ROLE_USER"));
+ when(user.getName()).thenReturn("user");
+ when(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any()))
+ .thenReturn(userDetails);
+
+ this.mvc.perform(get("/")
+ .principal(user)
+ .with(request -> {
+ request.addUserRole("ROLE_ADMIN");
+ request.addUserRole("ROLE_USER");
+ return request;
+ }))
+ .andExpect(authenticated().withRoles("USER"));
+ }
+
+ @EnableWebSecurity
+ public static class JeeCustomAuthenticatedUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
+ static AuthenticationUserDetailsService authenticationUserDetailsService =
+ mock(AuthenticationUserDetailsService.class);
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
+ .jee(jee ->
+ jee
+ .authenticatedUserDetailsService(authenticationUserDetailsService)
+ );
+ // @formatter:on
+ }
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java
index 3ef62bf4a8..86bf87a6be 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurerTests.java
@@ -37,10 +37,15 @@ import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -77,6 +82,26 @@ public class LogoutConfigurerTests {
}
}
+ @Test
+ public void configureWhenDefaultLogoutSuccessHandlerForHasNullLogoutHandlerInLambdaThenException() {
+ assertThatThrownBy(() -> this.spring.register(NullLogoutSuccessHandlerInLambdaConfig.class).autowire())
+ .isInstanceOf(BeanCreationException.class)
+ .hasRootCauseInstanceOf(IllegalArgumentException.class);
+ }
+
+ @EnableWebSecurity
+ static class NullLogoutSuccessHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .logout(logout ->
+ logout.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class))
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void configureWhenDefaultLogoutSuccessHandlerForHasNullMatcherThenException() {
assertThatThrownBy(() -> this.spring.register(NullMatcherConfig.class).autowire())
@@ -96,6 +121,26 @@ public class LogoutConfigurerTests {
}
}
+ @Test
+ public void configureWhenDefaultLogoutSuccessHandlerForHasNullMatcherInLambdaThenException() {
+ assertThatThrownBy(() -> this.spring.register(NullMatcherInLambdaConfig.class).autowire())
+ .isInstanceOf(BeanCreationException.class)
+ .hasRootCauseInstanceOf(IllegalArgumentException.class);
+ }
+
+ @EnableWebSecurity
+ static class NullMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .logout(logout ->
+ logout.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null)
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLogoutFilter() {
this.spring.register(ObjectPostProcessorConfig.class).autowire();
@@ -263,6 +308,29 @@ public class LogoutConfigurerTests {
}
}
+ @Test
+ public void logoutWhenCustomLogoutUrlInLambdaThenRedirectsToLogin() throws Exception {
+ this.spring.register(CsrfDisabledAndCustomLogoutInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/custom/logout"))
+ .andExpect(status().isFound())
+ .andExpect(redirectedUrl("/login?logout"));
+ }
+
+ @EnableWebSecurity
+ static class CsrfDisabledAndCustomLogoutInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .csrf()
+ .disable()
+ .logout(logout -> logout.logoutUrl("/custom/logout"));
+ // @formatter:on
+ }
+ }
+
// SEC-3170
@Test
public void configureWhenLogoutHandlerNullThenException() {
@@ -283,6 +351,24 @@ public class LogoutConfigurerTests {
}
}
+ @Test
+ public void configureWhenLogoutHandlerNullInLambdaThenException() {
+ assertThatThrownBy(() -> this.spring.register(NullLogoutHandlerInLambdaConfig.class).autowire())
+ .isInstanceOf(BeanCreationException.class)
+ .hasRootCauseInstanceOf(IllegalArgumentException.class);
+ }
+
+ @EnableWebSecurity
+ static class NullLogoutHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .logout(logout -> logout.addLogoutHandler(null));
+ // @formatter:on
+ }
+ }
+
// SEC-3170
@Test
public void rememberMeWhenRememberMeServicesNotLogoutHandlerThenRedirectsToLogin() throws Exception {
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java
index 83d0508057..9a66e356fd 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpBasicTests.java
@@ -125,9 +125,10 @@ public class NamespaceHttpBasicTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .anyRequest().hasRole("USER")
- .and()
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
.httpBasic(withDefaults());
// @formatter:on
}
@@ -174,9 +175,10 @@ public class NamespaceHttpBasicTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .anyRequest().hasRole("USER")
- .and()
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
.httpBasic(httpBasicConfig -> httpBasicConfig.realmName("Custom Realm"));
// @formatter:on
}
@@ -310,9 +312,10 @@ public class NamespaceHttpBasicTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .anyRequest().hasRole("USER")
- .and()
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
.httpBasic(httpBasicConfig ->
httpBasicConfig.authenticationEntryPoint(this.authenticationEntryPoint));
// @formatter:on
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java
index cd0bf72dec..a1ad03748d 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpLogoutTests.java
@@ -41,9 +41,11 @@ import org.springframework.test.web.servlet.ResultMatcher;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests to verify that all the functionality of attributes is present
@@ -83,6 +85,23 @@ public class NamespaceHttpLogoutTests {
}
}
+ @Test
+ @WithMockUser
+ public void logoutWhenDisabledInLambdaThenRespondsWithNotFound() throws Exception {
+ this.spring.register(HttpLogoutDisabledInLambdaConfig.class).autowire();
+
+ this.mvc.perform(post("/logout").with(csrf()).with(user("user")))
+ .andExpect(status().isNotFound());
+ }
+
+ @EnableWebSecurity
+ static class HttpLogoutDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.logout(AbstractHttpConfigurer::disable);
+ }
+ }
+
/**
* http/logout custom
*/
@@ -112,6 +131,35 @@ public class NamespaceHttpLogoutTests {
}
}
+ @Test
+ @WithMockUser
+ public void logoutWhenUsingVariousCustomizationsInLambdaThenMatchesNamespace() throws Exception {
+ this.spring.register(CustomHttpLogoutInLambdaConfig.class).autowire();
+
+ this.mvc.perform(post("/custom-logout").with(csrf()))
+ .andExpect(authenticated(false))
+ .andExpect(redirectedUrl("/logout-success"))
+ .andExpect(result -> assertThat(result.getResponse().getCookies()).hasSize(1))
+ .andExpect(cookie().maxAge("remove", 0))
+ .andExpect(session(Objects::nonNull));
+ }
+
+ @EnableWebSecurity
+ static class CustomHttpLogoutInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .logout(logout ->
+ logout.deleteCookies("remove")
+ .invalidateHttpSession(false)
+ .logoutUrl("/custom-logout")
+ .logoutSuccessUrl("/logout-success")
+ );
+ // @formatter:on
+ }
+ }
+
/**
* http/logout@success-handler-ref
*/
@@ -141,6 +189,32 @@ public class NamespaceHttpLogoutTests {
}
}
+ @Test
+ @WithMockUser
+ public void logoutWhenUsingSuccessHandlerRefInLambdaThenMatchesNamespace() throws Exception {
+ this.spring.register(SuccessHandlerRefHttpLogoutInLambdaConfig.class).autowire();
+
+ this.mvc.perform(post("/logout").with(csrf()))
+ .andExpect(authenticated(false))
+ .andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig"))
+ .andExpect(noCookies())
+ .andExpect(session(Objects::isNull));
+ }
+
+ @EnableWebSecurity
+ static class SuccessHandlerRefHttpLogoutInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
+ logoutSuccessHandler.setDefaultTargetUrl("/SuccessHandlerRefHttpLogoutConfig");
+
+ // @formatter:off
+ http
+ .logout(logout -> logout.logoutSuccessHandler(logoutSuccessHandler));
+ // @formatter:on
+ }
+ }
+
ResultMatcher authenticated(boolean authenticated) {
return result -> assertThat(
Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java
index eb4763bd55..0aea788b3d 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/NamespaceHttpServerAccessDeniedHandlerTests.java
@@ -83,6 +83,32 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
return new UsernamePasswordAuthenticationToken("user", null, AuthorityUtils.NO_AUTHORITIES);
}
+ @Test
+ public void requestWhenCustomAccessDeniedPageInLambdaThenForwardedToCustomPage() throws Exception {
+ this.spring.register(AccessDeniedPageInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/")
+ .with(authentication(user())))
+ .andExpect(status().isForbidden())
+ .andExpect(forwardedUrl("/AccessDeniedPageConfig"));
+ }
+
+ @EnableWebSecurity
+ static class AccessDeniedPageInLambdaConfig extends WebSecurityConfigurerAdapter {
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().denyAll()
+ )
+ .exceptionHandling(exceptionHandling ->
+ exceptionHandling.accessDeniedPage("/AccessDeniedPageConfig")
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void requestWhenCustomAccessDeniedHandlerThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(AccessDeniedHandlerRefConfig.class).autowire();
@@ -109,6 +135,40 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
}
}
+ @Test
+ public void requestWhenCustomAccessDeniedHandlerInLambdaThenBehaviorMatchesNamespace() throws Exception {
+ this.spring.register(AccessDeniedHandlerRefInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/")
+ .with(authentication(user())));
+
+ verify(AccessDeniedHandlerRefInLambdaConfig.accessDeniedHandler)
+ .handle(any(HttpServletRequest.class), any(HttpServletResponse.class), any(AccessDeniedException.class));
+ }
+
+ @EnableWebSecurity
+ static class AccessDeniedHandlerRefInLambdaConfig extends WebSecurityConfigurerAdapter {
+ static AccessDeniedHandler accessDeniedHandler = mock(AccessDeniedHandler.class);
+
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().denyAll()
+ )
+ .exceptionHandling(exceptionHandling ->
+ exceptionHandling.accessDeniedHandler(accessDeniedHandler())
+ );
+ // @formatter:on
+ }
+
+ @Bean
+ AccessDeniedHandler accessDeniedHandler() {
+ return accessDeniedHandler;
+ }
+ }
+
private T verifyBean(Class beanClass) {
return verify(this.spring.getContext().getBean(beanClass));
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java
index bc451f4c95..bd68d2ecec 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PortMapperConfigurerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -22,8 +22,11 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule;
+import org.springframework.security.web.PortMapperImpl;
import org.springframework.test.web.servlet.MockMvc;
+import java.util.Collections;
+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
@@ -61,4 +64,58 @@ public class PortMapperConfigurerTests {
.portMapper();
}
}
+
+ @Test
+ public void requestWhenPortMapperHttpMapsToInLambdaThenRedirectsToHttpsPort() throws Exception {
+ this.spring.register(HttpMapsToInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(get("http://localhost:543"))
+ .andExpect(redirectedUrl("https://localhost:123"));
+ }
+
+ @EnableWebSecurity
+ static class HttpMapsToInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .requiresChannel(requiresChannel ->
+ requiresChannel
+ .anyRequest().requiresSecure()
+ )
+ .portMapper(portMapper ->
+ portMapper
+ .http(543).mapsTo(123)
+ );
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenCustomPortMapperInLambdaThenRedirectsToHttpsPort() throws Exception {
+ this.spring.register(CustomPortMapperInLambdaConfig.class).autowire();
+
+ this.mockMvc.perform(get("http://localhost:543"))
+ .andExpect(redirectedUrl("https://localhost:123"));
+ }
+
+ @EnableWebSecurity
+ static class CustomPortMapperInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ PortMapperImpl customPortMapper = new PortMapperImpl();
+ customPortMapper.setPortMappings(Collections.singletonMap("543", "123"));
+ // @formatter:off
+ http
+ .requiresChannel(requiresChannel ->
+ requiresChannel
+ .anyRequest().requiresSecure()
+ )
+ .portMapper(portMapper ->
+ portMapper
+ .portMapper(customPortMapper)
+ );
+ // @formatter:on
+ }
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java
index 4c217ee2d9..1e3ee6018d 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RememberMeConfigurerTests.java
@@ -51,6 +51,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -299,6 +300,45 @@ public class RememberMeConfigurerTests {
}
}
+
+ @Test
+ public void loginWhenRememberMeConfiguredInLambdaThenRespondsWithRememberMeCookie() throws Exception {
+ this.spring.register(RememberMeInLambdaConfig.class).autowire();
+
+ this.mvc.perform(post("/login")
+ .with(csrf())
+ .param("username", "user")
+ .param("password", "password")
+ .param("remember-me", "true"))
+ .andExpect(cookie().exists("remember-me"));
+ }
+
+ @EnableWebSecurity
+ static class RememberMeInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
+ .formLogin(withDefaults())
+ .rememberMe(withDefaults());
+ // @formatter:on
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
@Test
public void loginWhenRememberMeTrueAndCookieDomainThenRememberMeCookieHasDomain() throws Exception {
this.spring.register(RememberMeCookieDomainConfig.class).autowire();
@@ -337,6 +377,46 @@ public class RememberMeConfigurerTests {
}
}
+ @Test
+ public void loginWhenRememberMeTrueAndCookieDomainInLambdaThenRememberMeCookieHasDomain() throws Exception {
+ this.spring.register(RememberMeCookieDomainInLambdaConfig.class).autowire();
+
+ this.mvc.perform(post("/login")
+ .with(csrf())
+ .param("username", "user")
+ .param("password", "password")
+ .param("remember-me", "true"))
+ .andExpect(cookie().exists("remember-me"))
+ .andExpect(cookie().domain("remember-me", "spring.io"));
+ }
+
+ @EnableWebSecurity
+ static class RememberMeCookieDomainInLambdaConfig extends WebSecurityConfigurerAdapter {
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("USER")
+ )
+ .formLogin(withDefaults())
+ .rememberMe(rememberMe ->
+ rememberMe
+ .rememberMeCookieDomain("spring.io")
+ );
+ // @formatter:on
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
@Test
public void configureWhenRememberMeCookieNameAndRememberMeServicesThenException() {
assertThatThrownBy(() -> this.spring.register(RememberMeCookieNameAndRememberMeServicesConfig.class).autowire())
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java
index 683a4951c2..7b16123165 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestCacheConfigurerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -33,6 +33,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.test.web.servlet.MockMvc;
@@ -42,6 +43,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -271,6 +273,93 @@ public class RequestCacheConfigurerTests {
}
}
+ @Test
+ public void getWhenRequestCacheIsDisabledInLambdaThenExceptionTranslationFilterDoesNotStoreRequest() throws Exception {
+ this.spring.register(RequestCacheDisabledInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
+
+ MockHttpSession session = (MockHttpSession)
+ this.mvc.perform(get("/bob"))
+ .andReturn().getRequest().getSession();
+
+ this.mvc.perform(formLogin(session))
+ .andExpect(redirectedUrl("/"));
+ }
+
+ @EnableWebSecurity
+ static class RequestCacheDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .formLogin(withDefaults())
+ .requestCache(RequestCacheConfigurer::disable);
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void getWhenRequestCacheInLambdaThenRedirectedToCachedPage() throws Exception {
+ this.spring.register(RequestCacheInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
+
+ MockHttpSession session = (MockHttpSession)
+ this.mvc.perform(get("/bob"))
+ .andReturn().getRequest().getSession();
+
+ this.mvc.perform(formLogin(session))
+ .andExpect(redirectedUrl("http://localhost/bob"));
+ }
+
+ @EnableWebSecurity
+ static class RequestCacheInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .formLogin(withDefaults())
+ .requestCache(withDefaults());
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void getWhenCustomRequestCacheInLambdaThenCustomRequestCacheUsed() throws Exception {
+ this.spring.register(CustomRequestCacheInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
+
+ MockHttpSession session = (MockHttpSession)
+ this.mvc.perform(get("/bob"))
+ .andReturn().getRequest().getSession();
+
+ this.mvc.perform(formLogin(session))
+ .andExpect(redirectedUrl("/"));
+ }
+
+ @EnableWebSecurity
+ static class CustomRequestCacheInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .formLogin(withDefaults())
+ .requestCache(requestCache ->
+ requestCache
+ .requestCache(new NullRequestCache())
+ );
+ // @formatter:on
+ }
+ }
+
@EnableWebSecurity
static class DefaultSecurityConfig {
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java
index c47b8f970f..4bc131761b 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/RequestMatcherConfigurerTests.java
@@ -71,4 +71,37 @@ public class RequestMatcherConfigurerTests {
// @formatter:on
}
}
+
+ @Test
+ public void authorizeRequestsWhenInvokedMultipleTimesInLambdaThenChainsPaths() throws Exception {
+ this.spring.register(AuthorizeRequestInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/oauth/abc"))
+ .andExpect(status().isForbidden());
+ this.mvc.perform(get("/api/abc"))
+ .andExpect(status().isForbidden());
+ }
+
+ @EnableWebSecurity
+ static class AuthorizeRequestInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .requestMatchers(requestMatchers ->
+ requestMatchers
+ .antMatchers("/api/**")
+ )
+ .requestMatchers(requestMatchers ->
+ requestMatchers
+ .antMatchers("/oauth/**")
+ )
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().denyAll()
+ );
+ // @formatter:on
+ }
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java
index b9b0939344..5d0419d959 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurerTests.java
@@ -28,14 +28,22 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.web.context.HttpRequestResponseHolder;
+import org.springframework.security.web.context.NullSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import javax.servlet.http.HttpSession;
+
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
+import static org.springframework.security.config.Customizer.withDefaults;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/**
@@ -151,4 +159,97 @@ public class SecurityContextConfigurerTests {
// @formatter:on
}
}
+
+ @Test
+ public void requestWhenSecurityContextWithDefaultsInLambdaThenSessionIsCreated() throws Exception {
+ this.spring.register(SecurityContextWithDefaultsInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+ HttpSession session = mvcResult.getRequest().getSession(false);
+ assertThat(session).isNotNull();
+ }
+
+ @EnableWebSecurity
+ static class SecurityContextWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .formLogin(withDefaults())
+ .securityContext(withDefaults());
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenSecurityContextDisabledInLambdaThenContextNotSavedInSession() throws Exception {
+ this.spring.register(SecurityContextDisabledInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+ HttpSession session = mvcResult.getRequest().getSession(false);
+ assertThat(session).isNull();
+ }
+
+ @EnableWebSecurity
+ static class SecurityContextDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .formLogin(withDefaults())
+ .securityContext(AbstractHttpConfigurer::disable);
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenNullSecurityContextRepositoryInLambdaThenContextNotSavedInSession() throws Exception {
+ this.spring.register(NullSecurityContextRepositoryInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(formLogin()).andReturn();
+ HttpSession session = mvcResult.getRequest().getSession(false);
+ assertThat(session).isNull();
+ }
+
+ @EnableWebSecurity
+ static class NullSecurityContextRepositoryInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .formLogin(withDefaults())
+ .securityContext(securityContext ->
+ securityContext
+ .securityContextRepository(new NullSecurityContextRepository())
+ );
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java
index dcf96fa2d8..b390d00493 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java
@@ -47,6 +47,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
@@ -230,6 +231,53 @@ public class ServletApiConfigurerTests {
}
}
+ @Test
+ public void requestWhenServletApiWithDefaultsInLambdaThenUsesDefaultRolePrefix() throws Exception {
+ this.spring.register(ServletApiWithDefaultsInLambdaConfig.class, AdminController.class).autowire();
+
+ this.mvc.perform(get("/admin")
+ .with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
+ .andExpect(status().isOk());
+ }
+
+ @EnableWebSecurity
+ static class ServletApiWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .servletApi(withDefaults());
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenRolePrefixInLambdaThenUsesCustomRolePrefix() throws Exception {
+ this.spring.register(RolePrefixInLambdaConfig.class, AdminController.class).autowire();
+
+ this.mvc.perform(get("/admin")
+ .with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN"))))
+ .andExpect(status().isOk());
+
+ this.mvc.perform(get("/admin")
+ .with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
+ .andExpect(status().isForbidden());
+ }
+
+ @EnableWebSecurity
+ static class RolePrefixInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .servletApi(servletApi ->
+ servletApi
+ .rolePrefix("PERMISSION_")
+ );
+ // @formatter:on
+ }
+ }
+
@RestController
static class AdminController {
@GetMapping("/admin")
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java
index 4278811084..5eaa4d78a7 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java
@@ -54,6 +54,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -201,6 +202,51 @@ public class SessionManagementConfigurerTests {
}
}
+ @Test
+ public void authenticateWhenNewSessionFixationProtectionInLambdaThenCreatesNewSession() throws Exception {
+ this.spring.register(SFPNewSessionInLambdaConfig.class).autowire();
+
+ MockHttpSession givenSession = new MockHttpSession();
+ String givenSessionId = givenSession.getId();
+ givenSession.setAttribute("name", "value");
+
+ MockHttpSession resultingSession = (MockHttpSession)
+ this.mvc.perform(get("/auth")
+ .session(givenSession)
+ .with(httpBasic("user", "password")))
+ .andExpect(status().isNotFound())
+ .andReturn().getRequest().getSession(false);
+
+ assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
+ assertThat(resultingSession.getAttribute("name")).isNull();
+ }
+
+ @EnableWebSecurity
+ static class SFPNewSessionInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .sessionManagement(sessionManagement ->
+ sessionManagement
+ .sessionFixation(sessionFixation ->
+ sessionFixation.newSession()
+ )
+ )
+ .httpBasic(withDefaults());
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
@Test
public void loginWhenUserLoggedInAndMaxSessionsIsOneThenLoginPrevented() throws Exception {
this.spring.register(ConcurrencyControlConfig.class).autowire();
@@ -262,6 +308,76 @@ public class SessionManagementConfigurerTests {
}
}
+ @Test
+ public void loginWhenUserLoggedInAndMaxSessionsOneInLambdaThenLoginPrevented() throws Exception {
+ this.spring.register(ConcurrencyControlInLambdaConfig.class).autowire();
+
+ this.mvc.perform(post("/login")
+ .with(csrf())
+ .param("username", "user")
+ .param("password", "password"));
+
+ this.mvc.perform(post("/login")
+ .with(csrf())
+ .param("username", "user")
+ .param("password", "password"))
+ .andExpect(status().isFound())
+ .andExpect(redirectedUrl("/login?error"));
+ }
+
+ @EnableWebSecurity
+ static class ConcurrencyControlInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .formLogin(withDefaults())
+ .sessionManagement(sessionManagement ->
+ sessionManagement
+ .sessionConcurrency(sessionConcurrency ->
+ sessionConcurrency
+ .maximumSessions(1)
+ .maxSessionsPreventsLogin(true)
+ )
+ );
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser(PasswordEncodedUser.user());
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenSessionCreationPolicyStateLessInLambdaThenNoSessionCreated() throws Exception {
+ this.spring.register(SessionCreationPolicyStateLessInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mvc.perform(get("/"))
+ .andReturn();
+ HttpSession session = mvcResult.getRequest().getSession(false);
+
+ assertThat(session).isNull();
+ }
+
+ @EnableWebSecurity
+ static class SessionCreationPolicyStateLessInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .sessionManagement(sessionManagement ->
+ sessionManagement
+ .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ );
+ // @formatter:on
+ }
+ }
+
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnSessionManagementFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java
index 49ca4e431b..f7c24c0013 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/X509ConfigurerTests.java
@@ -38,6 +38,7 @@ import java.security.cert.X509Certificate;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -122,6 +123,69 @@ public class X509ConfigurerTests {
}
}
+ @Test
+ public void x509WhenConfiguredInLambdaThenUsesDefaults() throws Exception {
+ this.spring.register(DefaultsInLambdaConfig.class).autowire();
+ X509Certificate certificate = loadCert("rod.cer");
+
+ this.mvc.perform(get("/")
+ .with(x509(certificate)))
+ .andExpect(authenticated().withUsername("rod"));
+ }
+
+ @EnableWebSecurity
+ static class DefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .x509(withDefaults());
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser("rod").password("password").roles("USER", "ADMIN");
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception {
+ this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire();
+ X509Certificate certificate = loadCert("rodatexampledotcom.cer");
+
+ this.mvc.perform(get("/")
+ .with(x509(certificate)))
+ .andExpect(authenticated().withUsername("rod"));
+ }
+
+ @EnableWebSecurity
+ static class SubjectPrincipalRegexInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .x509(x509 ->
+ x509
+ .subjectPrincipalRegex("CN=(.*?)@example.com(?:,|$)")
+ );
+ // @formatter:on
+ }
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+ // @formatter:off
+ auth
+ .inMemoryAuthentication()
+ .withUser("rod").password("password").roles("USER", "ADMIN");
+ // @formatter:on
+ }
+ }
+
private T loadCert(String location) {
try (InputStream is = new ClassPathResource(location).getInputStream()) {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java
index 269641783f..5a231dc28a 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2ClientConfigurerTests.java
@@ -65,6 +65,7 @@ import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -141,6 +142,19 @@ public class OAuth2ClientConfigurerTests {
"redirect_uri=http://localhost/client-1");
}
+ @Test
+ public void configureWhenOauth2ClientInLambdaThenRedirectForAuthorization() throws Exception {
+ this.spring.register(OAuth2ClientInLambdaConfig.class).autowire();
+
+ MvcResult mvcResult = this.mockMvc.perform(get("/oauth2/authorization/registration-1"))
+ .andExpect(status().is3xxRedirection())
+ .andReturn();
+ assertThat(mvcResult.getResponse().getRedirectedUrl()).matches("https://provider.com/oauth2/authorize\\?" +
+ "response_type=code&client_id=client-1&" +
+ "scope=user&state=.{15,}&" +
+ "redirect_uri=http://localhost/client-1");
+ }
+
@Test
public void configureWhenAuthorizationCodeResponseSuccessThenAuthorizedClientSaved() throws Exception {
this.spring.register(OAuth2ClientConfig.class).autowire();
@@ -248,4 +262,30 @@ public class OAuth2ClientConfigurerTests {
}
}
}
+
+ @EnableWebSecurity
+ @EnableWebMvc
+ static class OAuth2ClientInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2Client(withDefaults());
+ // @formatter:on
+ }
+
+ @Bean
+ public ClientRegistrationRepository clientRegistrationRepository() {
+ return clientRegistrationRepository;
+ }
+
+ @Bean
+ public OAuth2AuthorizedClientRepository authorizedClientRepository() {
+ return authorizedClientRepository;
+ }
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java
index f33c9d0201..a61a99f872 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java
@@ -176,6 +176,25 @@ public class OAuth2LoginConfigurerTests {
.isInstanceOf(OAuth2UserAuthority.class).hasToString("ROLE_USER");
}
+ @Test
+ public void requestWhenOauth2LoginInLambdaThenAuthenticationContainsOauth2UserAuthority() throws Exception {
+ loadConfig(OAuth2LoginInLambdaConfig.class);
+ OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest();
+ this.authorizationRequestRepository.saveAuthorizationRequest(
+ authorizationRequest, this.request, this.response);
+ this.request.setParameter("code", "code123");
+ this.request.setParameter("state", authorizationRequest.getState());
+
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+ Authentication authentication = this.securityContextRepository
+ .loadContext(new HttpRequestResponseHolder(this.request, this.response))
+ .getAuthentication();
+ assertThat(authentication.getAuthorities()).hasSize(1);
+ assertThat(authentication.getAuthorities()).first()
+ .isInstanceOf(OAuth2UserAuthority.class).hasToString("ROLE_USER");
+ }
+
// gh-6009
@Test
public void oauth2LoginWhenSuccessThenAuthenticationSuccessEventPublished() throws Exception {
@@ -303,6 +322,29 @@ public class OAuth2LoginConfigurerTests {
assertThat(this.response.getRedirectedUrl()).isEqualTo("https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1");
}
+ @Test
+ public void requestWhenOauth2LoginWithCustomAuthorizationRequestParametersThenParametersInRedirectedUrl()
+ throws Exception {
+ loadConfig(OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda.class);
+ OAuth2AuthorizationRequestResolver resolver = this.context.getBean(
+ OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda.class).resolver;
+ OAuth2AuthorizationRequest result = OAuth2AuthorizationRequest.authorizationCode()
+ .authorizationUri("https://accounts.google.com/authorize")
+ .clientId("client-id")
+ .state("adsfa")
+ .authorizationRequestUri("https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1")
+ .build();
+ when(resolver.resolve(any())).thenReturn(result);
+
+ String requestUri = "/oauth2/authorization/google";
+ this.request = new MockHttpServletRequest("GET", requestUri);
+ this.request.setServletPath(requestUri);
+
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+ assertThat(this.response.getRedirectedUrl()).isEqualTo("https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1");
+ }
+
// gh-5347
@Test
public void oauth2LoginWithOneClientConfiguredThenRedirectForAuthorization() throws Exception {
@@ -374,6 +416,19 @@ public class OAuth2LoginConfigurerTests {
assertThat(this.response.getRedirectedUrl()).matches("http://localhost/custom-login");
}
+ @Test
+ public void requestWhenOauth2LoginWithCustomLoginPageInLambdaThenRedirectCustomLoginPage() throws Exception {
+ loadConfig(OAuth2LoginConfigCustomLoginPageInLambda.class);
+
+ String requestUri = "/";
+ this.request = new MockHttpServletRequest("GET", requestUri);
+ this.request.setServletPath(requestUri);
+
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+ assertThat(this.response.getRedirectedUrl()).matches("http://localhost/custom-login");
+ }
+
@Test
public void oidcLogin() throws Exception {
// setup application context
@@ -400,6 +455,32 @@ public class OAuth2LoginConfigurerTests {
.isInstanceOf(OidcUserAuthority.class).hasToString("ROLE_USER");
}
+ @Test
+ public void requestWhenOauth2LoginInLambdaAndOidcThenAuthenticationContainsOidcUserAuthority() throws Exception {
+ // setup application context
+ loadConfig(OAuth2LoginInLambdaConfig.class, JwtDecoderFactoryConfig.class);
+
+ // setup authorization request
+ OAuth2AuthorizationRequest authorizationRequest = createOAuth2AuthorizationRequest("openid");
+ this.authorizationRequestRepository.saveAuthorizationRequest(
+ authorizationRequest, this.request, this.response);
+
+ // setup authentication parameters
+ this.request.setParameter("code", "code123");
+ this.request.setParameter("state", authorizationRequest.getState());
+
+ // perform test
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+ // assertions
+ Authentication authentication = this.securityContextRepository
+ .loadContext(new HttpRequestResponseHolder(this.request, this.response))
+ .getAuthentication();
+ assertThat(authentication.getAuthorities()).hasSize(1);
+ assertThat(authentication.getAuthorities()).first()
+ .isInstanceOf(OidcUserAuthority.class).hasToString("ROLE_USER");
+ }
+
@Test
public void oidcLoginCustomWithConfigurer() throws Exception {
// setup application context
@@ -521,6 +602,30 @@ public class OAuth2LoginConfigurerTests {
}
}
+ @EnableWebSecurity
+ static class OAuth2LoginInLambdaConfig extends CommonLambdaWebSecurityConfigurerAdapter
+ implements ApplicationListener {
+ static List EVENTS = new ArrayList<>();
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .clientRegistrationRepository(
+ new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))
+ );
+ // @formatter:on
+ super.configure(http);
+ }
+
+ @Override
+ public void onApplicationEvent(AuthenticationSuccessEvent event) {
+ EVENTS.add(event);
+ }
+ }
+
@EnableWebSecurity
static class OAuth2LoginConfigCustomWithConfigurer extends CommonWebSecurityConfigurerAdapter {
@Override
@@ -586,6 +691,28 @@ public class OAuth2LoginConfigurerTests {
}
}
+ @EnableWebSecurity
+ static class OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda extends CommonLambdaWebSecurityConfigurerAdapter {
+ private ClientRegistrationRepository clientRegistrationRepository =
+ new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION);
+
+ OAuth2AuthorizationRequestResolver resolver = mock(OAuth2AuthorizationRequestResolver.class);
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .clientRegistrationRepository(this.clientRegistrationRepository)
+ .authorizationEndpoint(authorizationEndpoint ->
+ authorizationEndpoint
+ .authorizationRequestResolver(this.resolver)
+ )
+ );
+ super.configure(http);
+ }
+ }
+
@EnableWebSecurity
static class OAuth2LoginConfigMultipleClients extends CommonWebSecurityConfigurerAdapter {
@Override
@@ -612,6 +739,23 @@ public class OAuth2LoginConfigurerTests {
}
}
+ @EnableWebSecurity
+ static class OAuth2LoginConfigCustomLoginPageInLambda extends CommonLambdaWebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .clientRegistrationRepository(
+ new InMemoryClientRegistrationRepository(GOOGLE_CLIENT_REGISTRATION))
+ .loginPage("/custom-login")
+ );
+ // @formatter:on
+ super.configure(http);
+ }
+ }
+
@EnableWebSecurity
static class OAuth2LoginConfigWithOidcLogoutSuccessHandler extends CommonWebSecurityConfigurerAdapter {
@Override
@@ -667,6 +811,45 @@ public class OAuth2LoginConfigurerTests {
}
}
+ private static abstract class CommonLambdaWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .securityContext(securityContext ->
+ securityContext
+ .securityContextRepository(securityContextRepository())
+ )
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .tokenEndpoint(tokenEndpoint ->
+ tokenEndpoint
+ .accessTokenResponseClient(createOauth2AccessTokenResponseClient())
+ )
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ .userService(createOauth2UserService())
+ .oidcUserService(createOidcUserService())
+ )
+ );
+ // @formatter:on
+ }
+
+ @Bean
+ SecurityContextRepository securityContextRepository() {
+ return new HttpSessionSecurityContextRepository();
+ }
+
+ @Bean
+ HttpSessionOAuth2AuthorizationRequestRepository oauth2AuthorizationRequestRepository() {
+ return new HttpSessionOAuth2AuthorizationRequestRepository();
+ }
+ }
+
@Configuration
static class JwtDecoderFactoryConfig {
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
index 03a913a21e..2bf95f5fa9 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
@@ -127,6 +127,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.oauth2.core.TestOAuth2AccessTokens.noScopes;
import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSetUri;
import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withPublicKey;
@@ -184,6 +185,19 @@ public class OAuth2ResourceServerConfigurerTests {
.andExpect(content().string("ok"));
}
+ @Test
+ public void getWhenUsingDefaultsInLambdaWithValidBearerTokenThenAcceptsRequest()
+ throws Exception {
+
+ this.spring.register(RestOperationsConfig.class, DefaultInLambdaConfig.class, BasicController.class).autowire();
+ mockRestOperations(jwks("Default"));
+ String token = this.token("ValidNoScopes");
+
+ this.mvc.perform(get("/").with(bearerToken(token)))
+ .andExpect(status().isOk())
+ .andExpect(content().string("ok"));
+ }
+
@Test
public void getWhenUsingJwkSetUriThenAcceptsRequest() throws Exception {
this.spring.register(WebServerConfig.class, JwkSetUriConfig.class, BasicController.class).autowire();
@@ -195,6 +209,16 @@ public class OAuth2ResourceServerConfigurerTests {
.andExpect(content().string("ok"));
}
+ @Test
+ public void getWhenUsingJwkSetUriInLambdaThenAcceptsRequest() throws Exception {
+ this.spring.register(WebServerConfig.class, JwkSetUriInLambdaConfig.class, BasicController.class).autowire();
+ mockWebServer(jwks("Default"));
+ String token = this.token("ValidNoScopes");
+
+ this.mvc.perform(get("/").with(bearerToken(token)))
+ .andExpect(status().isOk())
+ .andExpect(content().string("ok"));
+ }
@Test
public void getWhenUsingDefaultsWithExpiredBearerTokenThenInvalidToken()
@@ -756,6 +780,23 @@ public class OAuth2ResourceServerConfigurerTests {
.andExpect(content().string(JWT_SUBJECT));
}
+ @Test
+ public void requestWhenCustomJwtDecoderInLambdaOnDslThenUsed()
+ throws Exception {
+
+ this.spring.register(CustomJwtDecoderInLambdaOnDsl.class, BasicController.class).autowire();
+
+ CustomJwtDecoderInLambdaOnDsl config = this.spring.getContext().getBean(CustomJwtDecoderInLambdaOnDsl.class);
+ JwtDecoder decoder = config.decoder();
+
+ when(decoder.decode(anyString())).thenReturn(JWT);
+
+ this.mvc.perform(get("/authenticated")
+ .with(bearerToken(JWT_TOKEN)))
+ .andExpect(status().isOk())
+ .andExpect(content().string(JWT_SUBJECT));
+ }
+
@Test
public void requestWhenCustomJwtDecoderExposedAsBeanThenUsed()
throws Exception {
@@ -1067,6 +1108,17 @@ public class OAuth2ResourceServerConfigurerTests {
.andExpect(content().string("test-subject"));
}
+ @Test
+ public void getWhenOpaqueTokenInLambdaAndIntrospectingThenOk() throws Exception {
+ this.spring.register(RestOperationsConfig.class, OpaqueTokenInLambdaConfig.class, BasicController.class).autowire();
+ mockRestOperations(json("Active"));
+
+ this.mvc.perform(get("/authenticated")
+ .with(bearerToken("token")))
+ .andExpect(status().isOk())
+ .andExpect(content().string("test-subject"));
+ }
+
@Test
public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire();
@@ -1104,6 +1156,20 @@ public class OAuth2ResourceServerConfigurerTests {
verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
}
+ @Test
+ public void getWhenCustomIntrospectionAuthenticationManagerInLambdaThenUsed() throws Exception {
+ this.spring.register(OpaqueTokenAuthenticationManagerInLambdaConfig.class, BasicController.class).autowire();
+
+ when(bean(AuthenticationProvider.class).authenticate(any(Authentication.class)))
+ .thenReturn(INTROSPECTION_AUTHENTICATION_TOKEN);
+ this.mvc.perform(get("/authenticated")
+ .with(bearerToken("token")))
+ .andExpect(status().isOk())
+ .andExpect(content().string("mock-test-subject"));
+
+ verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
+ }
+
@Test
public void configureWhenOnlyIntrospectionUrlThenException() throws Exception {
assertThatCode(() -> this.spring.register(OpaqueTokenHalfConfiguredConfig.class).autowire())
@@ -1311,6 +1377,26 @@ public class OAuth2ResourceServerConfigurerTests {
}
}
+ @EnableWebSecurity
+ static class DefaultInLambdaConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(withDefaults())
+ );
+ // @formatter:on
+ }
+ }
+
@EnableWebSecurity
static class JwkSetUriConfig extends WebSecurityConfigurerAdapter {
@Value("${mockwebserver.url:https://example.org}")
@@ -1331,6 +1417,31 @@ public class OAuth2ResourceServerConfigurerTests {
}
}
+ @EnableWebSecurity
+ static class JwkSetUriInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Value("${mockwebserver.url:https://example.org}")
+ String jwkSetUri;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/requires-read-scope").access("hasAuthority('SCOPE_message:read')")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(jwt ->
+ jwt
+ .jwkSetUri(this.jwkSetUri)
+ )
+ );
+ // @formatter:on
+ }
+ }
+
@EnableWebSecurity
static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
@Value("${mockwebserver.url:https://example.org}")
@@ -1677,6 +1788,33 @@ public class OAuth2ResourceServerConfigurerTests {
}
}
+ @EnableWebSecurity
+ static class CustomJwtDecoderInLambdaOnDsl extends WebSecurityConfigurerAdapter {
+ JwtDecoder decoder = mock(JwtDecoder.class);
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(jwt ->
+ jwt
+ .decoder(decoder())
+ )
+ );
+ // @formatter:on
+ }
+
+ JwtDecoder decoder() {
+ return this.decoder;
+ }
+ }
+
@EnableWebSecurity
static class CustomJwtDecoderAsBean extends WebSecurityConfigurerAdapter {
@Override
@@ -1831,6 +1969,25 @@ public class OAuth2ResourceServerConfigurerTests {
}
}
+ @EnableWebSecurity
+ static class OpaqueTokenInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/requires-read-scope").hasAuthority("SCOPE_message:read")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .opaqueToken(withDefaults())
+ );
+ // @formatter:on
+ }
+ }
+
@EnableWebSecurity
static class OpaqueTokenAuthenticationManagerConfig extends WebSecurityConfigurerAdapter {
@Override
@@ -1852,6 +2009,32 @@ public class OAuth2ResourceServerConfigurerTests {
}
}
+ @EnableWebSecurity
+ static class OpaqueTokenAuthenticationManagerInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .opaqueToken(opaqueToken ->
+ opaqueToken
+ .authenticationManager(authenticationProvider()::authenticate)
+ )
+ );
+ // @formatter:on
+ }
+
+ @Bean
+ public AuthenticationProvider authenticationProvider() {
+ return mock(AuthenticationProvider.class);
+ }
+ }
+
@EnableWebSecurity
static class OpaqueAndJwtConfig extends WebSecurityConfigurerAdapter {
@Override
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java
index d18efe0b37..159c54967e 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/openid/OpenIDLoginConfigurerTests.java
@@ -16,8 +16,13 @@
package org.springframework.security.config.annotation.web.configurers.openid;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
import org.junit.Rule;
import org.junit.Test;
+import org.openid4java.consumer.ConsumerManager;
+import org.openid4java.discovery.DiscoveryInformation;
+import org.openid4java.message.AuthRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.ObjectPostProcessor;
@@ -26,13 +31,23 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule;
+import org.springframework.security.openid.OpenIDAttribute;
import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.openid.OpenIDAuthenticationProvider;
import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.openid4java.discovery.yadis.YadisResolver.YADIS_XRDS_LOCATION;
+import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -128,4 +143,167 @@ public class OpenIDLoginConfigurerTests {
// @formatter:on
}
}
+
+ @Test
+ public void requestWhenOpenIdLoginPageInLambdaThenRedirectsToLoginPAge() throws Exception {
+ this.spring.register(OpenIdLoginPageInLambdaConfig.class).autowire();
+
+ this.mvc.perform(get("/"))
+ .andExpect(status().isFound())
+ .andExpect(redirectedUrl("http://localhost/login/custom"));
+ }
+
+ @EnableWebSecurity
+ static class OpenIdLoginPageInLambdaConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .openidLogin(openIdLogin ->
+ openIdLogin
+ .loginPage("/login/custom")
+ );
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenAttributeExchangeConfiguredThenFetchAttributesMatchAttributeList() throws Exception {
+ OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
+ AuthRequest mockAuthRequest = mock(AuthRequest.class);
+ DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class);
+ when(mockAuthRequest.getDestinationUrl(anyBoolean())).thenReturn("mockUrl");
+ when(OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER.associate(any()))
+ .thenReturn(mockDiscoveryInformation);
+ when(OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(), any()))
+ .thenReturn(mockAuthRequest);
+ this.spring.register(OpenIdAttributesInLambdaConfig.class).autowire();
+
+ try ( MockWebServer server = new MockWebServer() ) {
+ String endpoint = server.url("/").toString();
+
+ server.enqueue(new MockResponse()
+ .addHeader(YADIS_XRDS_LOCATION, endpoint));
+ server.enqueue(new MockResponse()
+ .setBody(String.format("%s", endpoint)));
+
+ MvcResult mvcResult = this.mvc.perform(get("/login/openid")
+ .param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
+ .andExpect(status().isFound())
+ .andReturn();
+
+ Object attributeObject = mvcResult.getRequest().getSession().getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
+ assertThat(attributeObject).isInstanceOf(List.class);
+ List attributeList = (List) attributeObject;
+ assertThat(attributeList.stream().anyMatch(attribute ->
+ "nickname".equals(attribute.getName())
+ && "https://schema.openid.net/namePerson/friendly".equals(attribute.getType())))
+ .isTrue();
+ assertThat(attributeList.stream().anyMatch(attribute ->
+ "email".equals(attribute.getName())
+ && "https://schema.openid.net/contact/email".equals(attribute.getType())
+ && attribute.isRequired()
+ && attribute.getCount() == 2))
+ .isTrue();
+ }
+ }
+
+ @EnableWebSecurity
+ static class OpenIdAttributesInLambdaConfig extends WebSecurityConfigurerAdapter {
+ static ConsumerManager CONSUMER_MANAGER;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().permitAll()
+ )
+ .openidLogin(openIdLogin ->
+ openIdLogin
+ .consumerManager(CONSUMER_MANAGER)
+ .attributeExchange(attributeExchange ->
+ attributeExchange
+ .identifierPattern(".*")
+ .attribute(nicknameAttribute ->
+ nicknameAttribute
+ .name("nickname")
+ .type("https://schema.openid.net/namePerson/friendly")
+ )
+ .attribute(emailAttribute ->
+ emailAttribute
+ .name("email")
+ .type("https://schema.openid.net/contact/email")
+ .required(true)
+ .count(2)
+ )
+ )
+ );
+ // @formatter:on
+ }
+ }
+
+ @Test
+ public void requestWhenAttributeNameNotSpecifiedThenAttributeNameDefaulted()
+ throws Exception {
+ OpenIdAttributesNullNameConfig.CONSUMER_MANAGER = mock(ConsumerManager.class);
+ AuthRequest mockAuthRequest = mock(AuthRequest.class);
+ DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class);
+ when(mockAuthRequest.getDestinationUrl(anyBoolean())).thenReturn("mockUrl");
+ when(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.associate(any()))
+ .thenReturn(mockDiscoveryInformation);
+ when(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(), any()))
+ .thenReturn(mockAuthRequest);
+ this.spring.register(OpenIdAttributesNullNameConfig.class).autowire();
+
+ try ( MockWebServer server = new MockWebServer() ) {
+ String endpoint = server.url("/").toString();
+
+ server.enqueue(new MockResponse()
+ .addHeader(YADIS_XRDS_LOCATION, endpoint));
+ server.enqueue(new MockResponse()
+ .setBody(String.format("%s", endpoint)));
+
+ MvcResult mvcResult = this.mvc.perform(get("/login/openid")
+ .param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
+ .andExpect(status().isFound())
+ .andReturn();
+
+ Object attributeObject = mvcResult.getRequest().getSession().getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
+ assertThat(attributeObject).isInstanceOf(List.class);
+ List attributeList = (List) attributeObject;
+ assertThat(attributeList).hasSize(1);
+ assertThat(attributeList.get(0).getName()).isEqualTo("default-attribute");
+ }
+ }
+
+ @EnableWebSecurity
+ static class OpenIdAttributesNullNameConfig extends WebSecurityConfigurerAdapter {
+ static ConsumerManager CONSUMER_MANAGER;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().permitAll()
+ )
+ .openidLogin(openIdLogin ->
+ openIdLogin
+ .consumerManager(CONSUMER_MANAGER)
+ .attributeExchange(attributeExchange ->
+ attributeExchange
+ .identifierPattern(".*")
+ .attribute(withDefaults())
+ )
+ );
+ // @formatter:on
+ }
+ }
}
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/mvc.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/mvc.adoc
index a23b9bf0a1..7173999ca1 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/mvc.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/mvc.adoc
@@ -104,8 +104,10 @@ If we wanted to restrict access to this controller method to admin users, a deve
----
protected configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .antMatchers("/admin").hasRole("ADMIN");
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/admin").hasRole("ADMIN")
+ );
}
----
@@ -133,8 +135,10 @@ The following configuration will protect the same URLs that Spring MVC will matc
----
protected configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .mvcMatchers("/admin").hasRole("ADMIN");
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .mvcMatchers("/admin").hasRole("ADMIN")
+ );
}
----
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/oauth2.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/oauth2.adoc
index 511de42d09..0fb146b07b 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/oauth2.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/oauth2.adoc
@@ -16,15 +16,25 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .authorizationEndpoint()
- ...
- .redirectionEndpoint()
- ...
- .tokenEndpoint()
- ...
- .userInfoEndpoint()
- ...
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .authorizationEndpoint(authorizationEndpoint ->
+ authorizationEndpoint
+ ...
+ )
+ .redirectionEndpoint(redirectionEndpoint ->
+ redirectionEndpoint
+ ...
+ )
+ .tokenEndpoint(tokenEndpoint ->
+ tokenEndpoint
+ ...
+ )
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ ...
+ )
+ );
}
}
----
@@ -58,27 +68,34 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .clientRegistrationRepository(this.clientRegistrationRepository())
- .authorizedClientRepository(this.authorizedClientRepository())
- .authorizedClientService(this.authorizedClientService())
- .loginPage("/login")
- .authorizationEndpoint()
- .baseUri(this.authorizationRequestBaseUri())
- .authorizationRequestRepository(this.authorizationRequestRepository())
- .authorizationRequestResolver(this.authorizationRequestResolver())
- .and()
- .redirectionEndpoint()
- .baseUri(this.authorizationResponseBaseUri())
- .and()
- .tokenEndpoint()
- .accessTokenResponseClient(this.accessTokenResponseClient())
- .and()
- .userInfoEndpoint()
- .userAuthoritiesMapper(this.userAuthoritiesMapper())
- .userService(this.oauth2UserService())
- .oidcUserService(this.oidcUserService())
- .customUserType(GitHubOAuth2User.class, "github");
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .clientRegistrationRepository(this.clientRegistrationRepository())
+ .authorizedClientRepository(this.authorizedClientRepository())
+ .authorizedClientService(this.authorizedClientService())
+ .loginPage("/login")
+ .authorizationEndpoint(authorizationEndpoint ->
+ authorizationEndpoint
+ .baseUri(this.authorizationRequestBaseUri())
+ .authorizationRequestRepository(this.authorizationRequestRepository())
+ .authorizationRequestResolver(this.authorizationRequestResolver())
+ )
+ .redirectionEndpoint(redirectionEndpoint ->
+ redirectionEndpoint
+ .baseUri(this.authorizationResponseBaseUri())
+ )
+ .tokenEndpoint(tokenEndpoint ->
+ tokenEndpoint
+ .accessTokenResponseClient(this.accessTokenResponseClient())
+ )
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ .userAuthoritiesMapper(this.userAuthoritiesMapper())
+ .userService(this.oauth2UserService())
+ .oidcUserService(this.oidcUserService())
+ .customUserType(GitHubOAuth2User.class, "github")
+ )
+ );
}
}
----
@@ -123,12 +140,16 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .loginPage("/login/oauth2")
- ...
- .authorizationEndpoint()
- .baseUri("/login/oauth2/authorization")
- ....
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .loginPage("/login/oauth2")
+ ...
+ .authorizationEndpoint(authorizationEndpoint ->
+ authorizationEndpoint
+ .baseUri("/login/oauth2/authorization")
+ ...
+ )
+ );
}
}
----
@@ -171,10 +192,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .redirectionEndpoint()
- .baseUri("/login/oauth2/callback/*")
- ....
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .redirectionEndpoint(redirectionEndpoint ->
+ redirectionEndpoint
+ .baseUri("/login/oauth2/callback/*")
+ ...
+ )
+ );
}
}
----
@@ -234,10 +259,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .userInfoEndpoint()
- .userAuthoritiesMapper(this.userAuthoritiesMapper())
- ...
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ .userAuthoritiesMapper(this.userAuthoritiesMapper())
+ ...
+ )
+ );
}
private GrantedAuthoritiesMapper userAuthoritiesMapper() {
@@ -280,7 +309,8 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
- http.oauth2Login();
+ http
+ .oauth2Login(withDefaults());
}
@Bean
@@ -308,10 +338,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .userInfoEndpoint()
- .oidcUserService(this.oidcUserService())
- ...
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ .oidcUserService(this.oidcUserService())
+ ...
+ )
+ );
}
private OAuth2UserService oidcUserService() {
@@ -355,10 +389,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .userInfoEndpoint()
- .customUserType(GitHubOAuth2User.class, "github")
- ...
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ .customUserType(GitHubOAuth2User.class, "github")
+ ...
+ )
+ );
}
}
----
@@ -469,10 +507,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .userInfoEndpoint()
- .userService(this.oauth2UserService())
- ...
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ .userService(this.oauth2UserService())
+ ...
+ )
+ );
}
private OAuth2UserService oauth2UserService() {
@@ -501,10 +543,14 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Login()
- .userInfoEndpoint()
- .oidcUserService(this.oidcUserService())
- ...
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ .oidcUserService(this.oidcUserService())
+ ...
+ )
+ );
}
private OAuth2UserService oidcUserService() {
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc
index aac5044dd1..e2308674e1 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/expression-based.adoc
@@ -169,9 +169,11 @@ or in Java configuration
[source,java]
----
http
- .authorizeRequests()
- .antMatchers("/user/{userId}/**").access("@webSecurity.checkUserId(authentication,#userId)")
- ...
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/user/{userId}/**").access("@webSecurity.checkUserId(authentication,#userId)")
+ ...
+ );
----
In both configurations URLs that match would pass in the path variable (and convert it) into checkUserId method.
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc
index 5990618e51..36141a4426 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc
@@ -137,12 +137,12 @@ How does Spring Security know that we want to require all users to be authentica
----
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .formLogin()
- .and()
- .httpBasic();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .formLogin(withDefaults())
+ .httpBasic(withDefaults());
}
----
@@ -163,10 +163,6 @@ You will notice that this configuration is quite similar the XML Namespace confi
----
-The Java Configuration equivalent of closing an XML tag is expressed using the `and()` method which allows us to continue configuring the parent.
-If you read the code it also makes sense.
-I want to configure authorized requests __and__ configure form login __and__ configure HTTP Basic authentication.
-
[[jc-form]]
== Java Configuration and Form Login
You might be wondering where the login form came from when you were prompted to log in, since we made no mention of any HTML files or JSPs.
@@ -180,12 +176,15 @@ To do so we can update our configuration as seen below:
----
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .formLogin()
- .loginPage("/login") // <1>
- .permitAll(); // <2>
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .formLogin(formLogin ->
+ formLogin
+ .loginPage("/login") // <1>
+ .permitAll() // <2>
+ );
}
----
@@ -245,14 +244,14 @@ For example:
----
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests() <1>
- .antMatchers("/resources/**", "/signup", "/about").permitAll() <2>
- .antMatchers("/admin/**").hasRole("ADMIN") <3>
- .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") <4>
- .anyRequest().authenticated() <5>
- .and()
- // ...
- .formLogin();
+ .authorizeRequests(authorizeRequests -> // <1>
+ authorizeRequests
+ .antMatchers("/resources/**", "/signup", "/about").permitAll() // <2>
+ .antMatchers("/admin/**").hasRole("ADMIN") // <3>
+ .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // <4>
+ .anyRequest().authenticated() // <5>
+ )
+ .formLogin(withDefaults());
}
----
@@ -282,14 +281,15 @@ Similar to configuring login capabilities, however, you also have various option
----
protected void configure(HttpSecurity http) throws Exception {
http
- .logout() <1>
- .logoutUrl("/my/logout") <2>
- .logoutSuccessUrl("/my/index") <3>
- .logoutSuccessHandler(logoutSuccessHandler) <4>
- .invalidateHttpSession(true) <5>
- .addLogoutHandler(logoutHandler) <6>
- .deleteCookies(cookieNamesToClear) <7>
- .and()
+ .logout(logout -> // <1>
+ logout
+ .logoutUrl("/my/logout") // <2>
+ .logoutSuccessUrl("/my/index") // <3>
+ .logoutSuccessHandler(logoutSuccessHandler) // <4>
+ .invalidateHttpSession(true) // <5>
+ .addLogoutHandler(logoutHandler) // <6>
+ .deleteCookies(cookieNamesToClear) // <7>
+ )
...
}
----
@@ -510,11 +510,14 @@ The first is a `WebSecurityConfigurerAdapter` that configures the app as a resou
```java
protected void configure(HttpSecurity http) {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .jwt();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(withDefaults())
+ );
}
```
@@ -527,13 +530,18 @@ Replacing this is as simple as exposing the bean within the application:
public class MyCustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) {
http
- .authorizeRequests()
- .mvcMatchers("/messages/**").hasAuthority("SCOPE_message:read")
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .jwt()
- .jwtAuthenticationConverter(myConverter());
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .mvcMatchers("/messages/**").hasAuthority("SCOPE_message:read")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(jwt ->
+ jwt
+ .jwtAuthenticationConverter(myConverter())
+ )
+ );
}
}
```
@@ -565,12 +573,17 @@ An authorization server's JWK Set Uri can be configured <
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(jwt ->
+ jwt
+ .jwkSetUri("https://idp.example.com/.well-known/jwks.json")
+ )
+ );
}
}
```
@@ -587,12 +600,17 @@ More powerful than `jwkSetUri()` is `decoder()`, which will completely replace a
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .jwt()
- .decoder(myCustomDecoder());
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(jwt ->
+ jwt
+ .decoder(myCustomDecoder())
+ )
+ );
}
}
```
@@ -627,13 +645,16 @@ This means that to protect an endpoint or method with a scope derived from a JWT
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) {
http
- .authorizeRequests()
- .mvcMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
- .mvcMatchers("/messages/**").hasAuthority("SCOPE_messages")
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .jwt();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .mvcMatchers("/contacts/**").hasAuthority("SCOPE_contacts")
+ .mvcMatchers("/messages/**").hasAuthority("SCOPE_messages")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(withDefaults())
+ );
}
}
```
@@ -659,12 +680,17 @@ To this end, the DSL exposes `jwtAuthenticationConverter()`:
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .jwt()
- .jwtAuthenticationConverter(grantedAuthoritiesExtractor());
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(jwt ->
+ jwt
+ .jwtAuthenticationConverter(grantedAuthoritiesExtractor())
+ )
+ );
}
}
@@ -1078,10 +1104,11 @@ public class MultiHttpSecurityConfig {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**") <3>
- .authorizeRequests()
- .anyRequest().hasRole("ADMIN")
- .and()
- .httpBasic();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().hasRole("ADMIN")
+ )
+ .httpBasic(withDefaults());
}
}
@@ -1091,10 +1118,11 @@ public class MultiHttpSecurityConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .formLogin();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .formLogin(withDefaults());
}
}
}
@@ -1221,15 +1249,17 @@ For example, if you wanted to configure the `filterSecurityPublishAuthorizationS
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .withObjectPostProcessor(new ObjectPostProcessor() {
- public O postProcess(
- O fsi) {
- fsi.setPublishAuthorizationSuccess(true);
- return fsi;
- }
- });
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ .withObjectPostProcessor(new ObjectPostProcessor() {
+ public O postProcess(
+ O fsi) {
+ fsi.setPublishAuthorizationSuccess(true);
+ return fsi;
+ }
+ })
+ );
}
----
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-client.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-client.adoc
index f362a11f7c..74fb98708a 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-client.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-client.adoc
@@ -20,14 +20,18 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Client()
- .clientRegistrationRepository(this.clientRegistrationRepository())
- .authorizedClientRepository(this.authorizedClientRepository())
- .authorizedClientService(this.authorizedClientService())
- .authorizationCodeGrant()
- .authorizationRequestRepository(this.authorizationRequestRepository())
- .authorizationRequestResolver(this.authorizationRequestResolver())
- .accessTokenResponseClient(this.accessTokenResponseClient());
+ .oauth2Client(oauth2Client ->
+ oauth2Client
+ .clientRegistrationRepository(this.clientRegistrationRepository())
+ .authorizedClientRepository(this.authorizedClientRepository())
+ .authorizedClientService(this.authorizedClientService())
+ .authorizationCodeGrant(authorizationCodeGrant ->
+ authorizationCodeGrant
+ .authorizationRequestRepository(this.authorizationRequestRepository())
+ .authorizationRequestResolver(this.authorizationRequestResolver())
+ .accessTokenResponseClient(this.accessTokenResponseClient())
+ )
+ );
}
}
----
@@ -245,10 +249,14 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Client()
- .authorizationCodeGrant()
- .authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
- ...
+ .oauth2Client(oauth2Client ->
+ oauth2Client
+ .authorizationCodeGrant(authorizationCodeGrant ->
+ authorizationCodeGrant
+ .authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
+ ...
+ )
+ );
}
private AuthorizationRequestRepository cookieAuthorizationRequestRepository() {
@@ -285,14 +293,19 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .oauth2Login()
- .authorizationEndpoint()
- .authorizationRequestResolver(
- new CustomAuthorizationRequestResolver(
- this.clientRegistrationRepository)); <1>
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .authorizationEndpoint(authorizationEndpoint ->
+ authorizationEndpoint
+ .authorizationRequestResolver(
+ new CustomAuthorizationRequestResolver(
+ this.clientRegistrationRepository)) <1>
+ )
+ );
}
}
@@ -422,10 +435,14 @@ public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .oauth2Client()
- .authorizationCodeGrant()
- .accessTokenResponseClient(this.customAccessTokenResponseClient())
- ...
+ .oauth2Client(oauth2Client ->
+ oauth2Client
+ .authorizationCodeGrant(authorizationCodeGrant ->
+ authorizationCodeGrant
+ .accessTokenResponseClient(this.customAccessTokenResponseClient())
+ ...
+ )
+ );
}
private OAuth2AccessTokenResponseClient customAccessTokenResponseClient() {
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-login.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-login.adoc
index 5d5307e65d..adead1a92d 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-login.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-login.adoc
@@ -285,10 +285,11 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .oauth2Login();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2Login(withDefaults());
}
}
----
@@ -310,10 +311,11 @@ public class OAuth2LoginConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .oauth2Login();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2Login(withDefaults());
}
}
@@ -358,10 +360,11 @@ public class OAuth2LoginConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .oauth2Login();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2Login(withDefaults());
}
}
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/web/cors.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/web/cors.adoc
index 11fd3f9e39..17283ae6a9 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/web/cors.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/web/cors.adoc
@@ -18,7 +18,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
- .cors().and()
+ .cors(withDefaults())
...
}
@@ -59,7 +59,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
http
// if Spring MVC is on classpath and no CorsConfigurationSource is provided,
// Spring Security will use CORS configuration provided to Spring MVC
- .cors().and()
+ .cors(withDefaults())
...
}
}
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/web/csrf.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/web/csrf.adoc
index 957950a5f4..aa4e6b8215 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/web/csrf.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/web/csrf.adoc
@@ -187,7 +187,9 @@ WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .csrf().disable();
+ .csrf(csrf ->
+ csrf.disable()
+ );
}
}
----
@@ -314,8 +316,10 @@ public class WebSecurityConfig extends
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .csrf()
- .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
+ .csrf(csrf ->
+ csrf
+ .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
+ );
}
}
----
@@ -391,8 +395,10 @@ WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .logout()
- .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
+ .logout(logout ->
+ logout
+ .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
+ );
}
}
----
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/web/headers.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/web/headers.adoc
index 26e0fe5157..72cfc6c20e 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/web/headers.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/web/headers.adoc
@@ -60,9 +60,15 @@ public class WebSecurityConfig extends
protected void configure(HttpSecurity http) throws Exception {
http
// ...
- .headers()
- .frameOptions().sameOrigin()
- .httpStrictTransportSecurity().disable();
+ .headers(headers ->
+ headers
+ .frameOptions(frameOptions ->
+ frameOptions.sameOrigin()
+ )
+ .httpStrictTransportSecurity(hsts ->
+ hsts.disable()
+ )
+ );
}
}
----
@@ -92,15 +98,17 @@ If you are using Spring Security's Java Configuration the following will only ad
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- // do not use any default headers unless explicitly listed
- .defaultsDisabled()
- .cacheControl();
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ // do not use any default headers unless explicitly listed
+ .defaultsDisabled()
+ .cacheControl(withDefaults())
+ );
+ }
}
----
@@ -126,12 +134,14 @@ If necessary, you can disable all of the HTTP Security response headers with the
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers().disable();
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers.disable()
+ );
+ }
}
----
@@ -182,14 +192,16 @@ Similarly, you can enable only cache control within Java Configuration with the
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .defaultsDisabled()
- .cacheControl();
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .cacheControl(withDefaults())
+ );
+ }
}
----
@@ -263,14 +275,16 @@ If you want more control over the headers, you can explicitly specify the conten
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .defaultsDisabled()
- .contentTypeOptions();
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .defaultsDisabled()
+ .contentTypeOptions(withDefaults())
+ );
+ }
}
----
@@ -327,16 +341,20 @@ Similarly, you can enable only HSTS headers with Java Configuration:
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .httpStrictTransportSecurity()
- .includeSubdomains(true)
- .preload(true)
- .maxAgeSeconds(31536000);
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .httpStrictTransportSecurity(hsts ->
+ hsts
+ .includeSubDomains(true)
+ .preload(true)
+ .maxAgeInSeconds(31536000)
+ )
+ );
+ }
}
----
@@ -399,16 +417,20 @@ Similarly, you can enable HPKP headers with Java Configuration:
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .httpPublicKeyPinning()
- .includeSubdomains(true)
- .reportUri("https://example.net/pkp-report")
- .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
- }
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .httpPublicKeyPinning(hpkp ->
+ hpkp
+ .includeSubDomains(true)
+ .reportUri("https://example.net/pkp-report")
+ .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=")
+ )
+ );
+ }
}
----
@@ -461,14 +483,18 @@ Similarly, you can customize frame options to use the same origin within Java Co
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .frameOptions()
- .sameOrigin();
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .frameOptions(frameOptions ->
+ frameOptions
+ .sameOrigin()
+ )
+ );
+ }
}
----
@@ -511,14 +537,18 @@ Similarly, you can customize XSS protection within Java Configuration with the f
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .xssProtection()
- .block(false);
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .xssProtection(xssProtection ->
+ xssProtection
+ .block(false)
+ )
+ );
+ }
}
----
@@ -625,13 +655,18 @@ Similarly, you can enable the CSP header using Java configuration as shown below
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .contentSecurityPolicy("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/");
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .contentSecurityPolicy(csp ->
+ csp
+ .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
+ )
+ );
+ }
}
----
@@ -643,14 +678,19 @@ To enable the CSP _'report-only'_ header, provide the following Java configurati
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .contentSecurityPolicy("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
- .reportOnly();
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .contentSecurityPolicy(csp ->
+ csp
+ .policyDirectives("script-src 'self' https://trustedscripts.example.com; object-src https://trustedplugins.example.com; report-uri /csp-report-endpoint/")
+ .reportOnly()
+ )
+ );
+ }
}
----
@@ -707,13 +747,18 @@ Similarly, you can enable the Referrer Policy header using Java configuration as
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .referrerPolicy(ReferrerPolicy.SAME_ORIGIN);
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .referrerPolicy(referrerPolicy ->
+ referrerPolicy
+ .policy(ReferrerPolicy.SAME_ORIGIN)
+ )
+ );
+ }
}
----
@@ -757,13 +802,15 @@ Similarly, you can enable the Feature Policy header using Java configuration as
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .featurePolicy("geolocation 'self'");
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .featurePolicy("geolocation 'self'")
+ );
+ }
}
----
@@ -804,13 +851,15 @@ Similarly, the headers could be added to the response using Java Configuration a
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"));
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .addHeaderWriter(new StaticHeadersWriter("X-Custom-Security-Header","header-value"))
+ );
+ }
}
----
@@ -849,13 +898,15 @@ We could also restrict framing of content to the same origin with Java configura
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- http
- // ...
- .headers()
- .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN));
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN))
+ );
+ }
}
----
@@ -903,17 +954,21 @@ We could also prevent framing of content to the log in page using java configura
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
-@Override
-protected void configure(HttpSecurity http) throws Exception {
- RequestMatcher matcher = new AntPathRequestMatcher("/login");
- DelegatingRequestMatcherHeaderWriter headerWriter =
- new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
- http
- // ...
- .headers()
- .frameOptions().disabled()
- .addHeaderWriter(headerWriter);
-}
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ RequestMatcher matcher = new AntPathRequestMatcher("/login");
+ DelegatingRequestMatcherHeaderWriter headerWriter =
+ new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
+ http
+ // ...
+ .headers(headers ->
+ headers
+ .frameOptions(frameOptions ->
+ frameOptions.disable()
+ )
+ .addHeaderWriter(headerWriter)
+ );
+ }
}
----
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/web/websocket.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/web/websocket.adoc
index 0553b46023..8dd70cb2c6 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/web/websocket.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/web/websocket.adoc
@@ -323,9 +323,13 @@ public class WebSecurityConfig extends
protected void configure(HttpSecurity http) throws Exception {
http
// ...
- .headers()
- .frameOptions()
- .sameOrigin();
+ .headers(headers ->
+ headers
+ .frameOptions(frameOptions ->
+ frameOptions
+ .sameOrigin()
+ )
+ );
}
}
----
@@ -356,18 +360,23 @@ public class WebSecurityConfig
@Override
protected void configure(HttpSecurity http) throws Exception {
-
http
- .csrf()
- // ignore our stomp endpoints since they are protected using Stomp headers
- .ignoringAntMatchers("/chat/**")
- .and()
- .headers()
- // allow same origin to frame our site to support iframe SockJS
- .frameOptions().sameOrigin()
- .and()
- .authorizeRequests()
-
+ .csrf(csrf ->
+ csrf
+ // ignore our stomp endpoints since they are protected using Stomp headers
+ .ignoringAntMatchers("/chat/**")
+ )
+ .headers(headers ->
+ headers
+ // allow same origin to frame our site to support iframe SockJS
+ .frameOptions(frameOptions ->
+ frameOptions
+ .sameOrigin()
+ )
+ )
+ .authorizeRequests(authorizeRequests ->
+ ...
+ )
...
----
diff --git a/samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
index e6d09b2448..7bb3d9e64d 100644
--- a/samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
+++ b/samples/boot/helloworld/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -32,11 +32,16 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .antMatchers("/css/**", "/index").permitAll()
- .antMatchers("/user/**").hasRole("USER")
- .and()
- .formLogin().loginPage("/login").failureUrl("/login-error");
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/css/**", "/index").permitAll()
+ .antMatchers("/user/**").hasRole("USER")
+ )
+ .formLogin(formLogin ->
+ formLogin
+ .loginPage("/login")
+ .failureUrl("/login-error")
+ );
}
// @formatter:on
diff --git a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
index d176bd694c..848622a047 100644
--- a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
+++ b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -358,15 +358,21 @@ public class OAuth2LoginApplicationTests {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .oauth2Login()
- .tokenEndpoint()
- .accessTokenResponseClient(this.mockAccessTokenResponseClient())
- .and()
- .userInfoEndpoint()
- .userService(this.mockUserService());
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .oauth2Login(oauth2Login ->
+ oauth2Login
+ .tokenEndpoint(tokenEndpoint ->
+ tokenEndpoint
+ .accessTokenResponseClient(this.mockAccessTokenResponseClient())
+ )
+ .userInfoEndpoint(userInfoEndpoint ->
+ userInfoEndpoint
+ .userService(this.mockUserService())
+ )
+ );
}
// @formatter:on
diff --git a/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
index 53e0a134a0..827a9628f7 100644
--- a/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
+++ b/samples/boot/oauth2resourceserver-jwe/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -46,6 +46,8 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
+import static org.springframework.security.config.Customizer.withDefaults;
+
/**
* @author Josh Cummings
*/
@@ -66,12 +68,15 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .antMatchers("/message/**").hasAuthority("SCOPE_message:read")
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .jwt();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/message/**").hasAuthority("SCOPE_message:read")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(withDefaults())
+ );
// @formatter:on
}
diff --git a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
index b8bd55b467..1c65ea247f 100644
--- a/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
+++ b/samples/boot/oauth2resourceserver-multitenancy/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
@@ -51,12 +51,15 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .antMatchers("/**/message/**").hasAuthority("SCOPE_message:read")
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .authenticationManagerResolver(multitenantAuthenticationManager());
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/**/message/**").hasAuthority("SCOPE_message:read")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .authenticationManagerResolver(multitenantAuthenticationManager())
+ );
// @formatter:on
}
diff --git a/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
index 03505b3d7e..ae7cf6736c 100644
--- a/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
+++ b/samples/boot/oauth2resourceserver-opaque/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
@@ -34,14 +34,19 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .mvcMatchers("/message/**").hasAuthority("SCOPE_message:read")
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .opaqueToken()
- .introspectionUri(this.introspectionUri)
- .introspectionClientCredentials(this.clientId, this.clientSecret);
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .mvcMatchers("/message/**").hasAuthority("SCOPE_message:read")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .opaqueToken(opaqueToken ->
+ opaqueToken
+ .introspectionUri(this.introspectionUri)
+ .introspectionClientCredentials(this.clientId, this.clientSecret)
+ )
+ );
// @formatter:on
}
}
diff --git a/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
index 135b6b5b24..67d74d9e25 100644
--- a/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
+++ b/samples/boot/oauth2resourceserver-static/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
@@ -38,13 +38,17 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .antMatchers("/message/**").hasAuthority("SCOPE_message:read")
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .jwt()
- .decoder(jwtDecoder());
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/message/**").hasAuthority("SCOPE_message:read")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(jwt ->
+ jwt.decoder(jwtDecoder())
+ )
+ );
// @formatter:on
}
diff --git a/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java b/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
index 70d5bc0b5b..23c3a4a74c 100644
--- a/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
+++ b/samples/boot/oauth2resourceserver/src/main/java/sample/OAuth2ResourceServerSecurityConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -19,6 +19,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import static org.springframework.security.config.Customizer.withDefaults;
+
/**
* @author Josh Cummings
*/
@@ -29,12 +31,15 @@ public class OAuth2ResourceServerSecurityConfiguration extends WebSecurityConfig
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
- .authorizeRequests()
- .antMatchers("/message/**").hasAuthority("SCOPE_message:read")
- .anyRequest().authenticated()
- .and()
- .oauth2ResourceServer()
- .jwt();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/message/**").hasAuthority("SCOPE_message:read")
+ .anyRequest().authenticated()
+ )
+ .oauth2ResourceServer(oauth2ResourceServer ->
+ oauth2ResourceServer
+ .jwt(withDefaults())
+ );
// @formatter:on
}
}
diff --git a/samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java b/samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java
index de8b5b5a6f..80cae2f658 100644
--- a/samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java
+++ b/samples/boot/oauth2webclient/src/main/java/sample/config/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * 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.
@@ -24,6 +24,8 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import static org.springframework.security.config.Customizer.withDefaults;
+
/**
* @author Joe Grandja
*/
@@ -33,15 +35,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .mvcMatchers("/", "/public/**").permitAll()
- .anyRequest().authenticated()
- .and()
- .formLogin()
- .and()
- .oauth2Login()
- .and()
- .oauth2Client();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .mvcMatchers("/", "/public/**").permitAll()
+ .anyRequest().authenticated()
+ )
+ .formLogin(withDefaults())
+ .oauth2Login(withDefaults())
+ .oauth2Client(withDefaults());
}
@Bean
diff --git a/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
index d2c9501cf7..d71dd73fc7 100644
--- a/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
+++ b/samples/javaconfig/concurrency/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -22,6 +22,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import static org.springframework.security.config.Customizer.withDefaults;
+
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@@ -40,14 +42,19 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(
HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .formLogin()
- .and()
- .sessionManagement()
- .maximumSessions(1)
- .expiredUrl("/login?expired");
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .formLogin(withDefaults())
+ .sessionManagement(sessionManagement ->
+ sessionManagement
+ .sessionConcurrency(sessionConcurrency ->
+ sessionConcurrency
+ .maximumSessions(1)
+ .expiredUrl("/login?expired")
+ )
+ );
}
// @formatter:on
}
diff --git a/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
index e2ec33a61d..5b002bade0 100644
--- a/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
+++ b/samples/javaconfig/form/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -29,16 +29,20 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .antMatchers("/resources/**").permitAll()
- .anyRequest().authenticated()
- .and()
- .formLogin()
- .loginPage("/login")
- .permitAll()
- .and()
- .logout()
- .permitAll();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/resources/**").permitAll()
+ .anyRequest().authenticated()
+ )
+ .formLogin(formLogin ->
+ formLogin
+ .loginPage("/login")
+ .permitAll()
+ )
+ .logout(logout ->
+ logout
+ .permitAll()
+ );
}
// @formatter:on
diff --git a/samples/javaconfig/openid/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/openid/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
index 0b21d482e9..dc9134832c 100644
--- a/samples/javaconfig/openid/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
+++ b/samples/javaconfig/openid/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -26,46 +26,71 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .antMatchers("/resources/**").permitAll()
- .anyRequest().authenticated()
- .and()
- .openidLogin()
- .loginPage("/login")
- .permitAll()
- .authenticationUserDetailsService(new CustomUserDetailsService())
- .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://axschema.org/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);
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/resources/**").permitAll()
+ .anyRequest().authenticated()
+ )
+ .openidLogin(openidLogin ->
+ openidLogin
+ .loginPage("/login")
+ .permitAll()
+ .authenticationUserDetailsService(new CustomUserDetailsService())
+ .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://axschema.org/contact/email")
+ .required(true)
+ )
+ .attribute(fullnameAttribute ->
+ fullnameAttribute
+ .name("fullname")
+ .type("https://axschema.org/namePerson")
+ .required(true)
+ )
+ )
+ .attributeExchange(myopenidExchange ->
+ myopenidExchange
+ .identifierPattern(".*myopenid.com.*")
+ .attribute(emailAttribute ->
+ emailAttribute
+ .name("email")
+ .type("https://schema.openid.net/contact/email")
+ .required(true)
+ )
+ .attribute(fullnameAttribute ->
+ fullnameAttribute
+ .name("fullname")
+ .type("https://schema.openid.net/namePerson")
+ .required(true)
+ )
+ )
+ );
}
// @formatter:on
}
diff --git a/samples/javaconfig/preauth/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/preauth/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
index 97b95313b2..1544f08b3b 100644
--- a/samples/javaconfig/preauth/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
+++ b/samples/javaconfig/preauth/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -26,12 +26,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .antMatchers("/login", "/resources/**").permitAll()
- .anyRequest().authenticated()
- .and()
- .jee()
- .mappableRoles("USER", "ADMIN");
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/login", "/resources/**").permitAll()
+ .anyRequest().authenticated()
+ )
+ .jee(jee ->
+ jee
+ .mappableRoles("USER", "ADMIN")
+ );
}
// @formatter:on
}
diff --git a/samples/javaconfig/rememberme/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/rememberme/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
index 20e1e09a89..c2e36065a0 100644
--- a/samples/javaconfig/rememberme/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
+++ b/samples/javaconfig/rememberme/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -21,6 +21,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import static org.springframework.security.config.Customizer.withDefaults;
+
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@@ -39,15 +41,17 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .antMatchers("/resources/**").permitAll()
- .anyRequest().authenticated()
- .and()
- .formLogin()
- .loginPage("/login")
- .permitAll()
- .and()
- .rememberMe();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .antMatchers("/resources/**").permitAll()
+ .anyRequest().authenticated()
+ )
+ .formLogin(formLogin ->
+ formLogin
+ .loginPage("/login")
+ .permitAll()
+ )
+ .rememberMe(withDefaults());
}
// @formatter:on
}
diff --git a/samples/javaconfig/x509/src/main/java/org/springframework/security/samples/config/SecurityConfig.java b/samples/javaconfig/x509/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
index ef7850625f..1fa5356df4 100644
--- a/samples/javaconfig/x509/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
+++ b/samples/javaconfig/x509/src/main/java/org/springframework/security/samples/config/SecurityConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * 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.
@@ -21,6 +21,8 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import static org.springframework.security.config.Customizer.withDefaults;
+
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@@ -40,10 +42,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
- .authorizeRequests()
- .anyRequest().authenticated()
- .and()
- .x509();
+ .authorizeRequests(authorizeRequests ->
+ authorizeRequests
+ .anyRequest().authenticated()
+ )
+ .x509(withDefaults());
}
// @formatter:on
}
diff --git a/web/src/main/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriter.java b/web/src/main/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriter.java
index 12ad08e978..4ae86198f3 100644
--- a/web/src/main/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriter.java
+++ b/web/src/main/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriter.java
@@ -81,10 +81,20 @@ public final class ContentSecurityPolicyHeaderWriter implements HeaderWriter {
private static final String CONTENT_SECURITY_POLICY_REPORT_ONLY_HEADER = "Content-Security-Policy-Report-Only";
+ private static final String DEFAULT_SRC_SELF_POLICY = "default-src 'self'";
+
private String policyDirectives;
private boolean reportOnly;
+ /**
+ * Creates a new instance. Default value: default-src 'self'
+ */
+ public ContentSecurityPolicyHeaderWriter() {
+ setPolicyDirectives(DEFAULT_SRC_SELF_POLICY);
+ this.reportOnly = false;
+ }
+
/**
* Creates a new instance
*
diff --git a/web/src/test/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriterTests.java b/web/src/test/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriterTests.java
index 5ff062f434..2f3c7914e8 100644
--- a/web/src/test/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriterTests.java
+++ b/web/src/test/java/org/springframework/security/web/header/writers/ContentSecurityPolicyHeaderWriterTests.java
@@ -43,6 +43,15 @@ public class ContentSecurityPolicyHeaderWriterTests {
writer = new ContentSecurityPolicyHeaderWriter(DEFAULT_POLICY_DIRECTIVES);
}
+ @Test
+ public void writeHeadersWhenNoPolicyDirectivesThenUsesDefault() {
+ ContentSecurityPolicyHeaderWriter noPolicyWriter = new ContentSecurityPolicyHeaderWriter();
+ noPolicyWriter.writeHeaders(request, response);
+
+ assertThat(response.getHeaderNames()).hasSize(1);
+ assertThat(response.getHeader("Content-Security-Policy")).isEqualTo(DEFAULT_POLICY_DIRECTIVES);
+ }
+
@Test
public void writeHeadersContentSecurityPolicyDefault() {
writer.writeHeaders(request, response);
@@ -64,6 +73,16 @@ public class ContentSecurityPolicyHeaderWriterTests {
assertThat(response.getHeader("Content-Security-Policy")).isEqualTo(policyDirectives);
}
+ @Test
+ public void writeHeadersWhenNoPolicyDirectivesReportOnlyThenUsesDefault() {
+ ContentSecurityPolicyHeaderWriter noPolicyWriter = new ContentSecurityPolicyHeaderWriter();
+ writer.setReportOnly(true);
+ noPolicyWriter.writeHeaders(request, response);
+
+ assertThat(response.getHeaderNames()).hasSize(1);
+ assertThat(response.getHeader("Content-Security-Policy")).isEqualTo(DEFAULT_POLICY_DIRECTIVES);
+ }
+
@Test
public void writeHeadersContentSecurityPolicyReportOnlyDefault() {
writer.setReportOnly(true);