DSL nested builder for HTTP security

DSL nested builder for HTTP security

Fixes gh-5557
This commit is contained in:
Rob Winch 2019-07-12 16:09:19 -05:00 committed by GitHub
commit ea54d9014d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 5281 additions and 519 deletions

View File

@ -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<H extends HttpSecurityBuilder<H>> extends
return contentTypeOptions.enable();
}
/**
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the <a href=
* "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
* >X-Content-Type-Options</a>:
*
* <pre>
* X-Content-Type-Options: nosniff
* </pre>
*
* @param contentTypeOptionsCustomizer the {@link Customizer} to provide more options for
* the {@link ContentTypeOptionsConfig}
* @return the {@link HeadersConfigurer} for additional customizations
* @throws Exception
*/
public HeadersConfigurer<H> contentTypeOptions(Customizer<ContentTypeOptionsConfig> contentTypeOptionsCustomizer)
throws Exception {
contentTypeOptionsCustomizer.customize(contentTypeOptions.enable());
return HeadersConfigurer.this;
}
public final class ContentTypeOptionsConfig {
private XContentTypeOptionsHeaderWriter writer;
@ -174,6 +197,25 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
return xssProtection.enable();
}
/**
* <strong>Note this is not comprehensive XSS protection!</strong>
*
* <p>
* Allows customizing the {@link XXssProtectionHeaderWriter} which adds the <a href=
* "https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
* >X-XSS-Protection header</a>
* </p>
*
* @param xssCustomizer the {@link Customizer} to provide more options for
* the {@link XXssConfig}
* @return the {@link HeadersConfigurer} for additional customizations
* @throws Exception
*/
public HeadersConfigurer<H> xssProtection(Customizer<XXssConfig> xssCustomizer) throws Exception {
xssCustomizer.customize(xssProtection.enable());
return HeadersConfigurer.this;
}
public final class XXssConfig {
private XXssProtectionHeaderWriter writer;
@ -268,6 +310,26 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
return cacheControl.enable();
}
/**
* Allows customizing the {@link CacheControlHeadersWriter}. Specifically it adds the
* following headers:
* <ul>
* <li>Cache-Control: no-cache, no-store, max-age=0, must-revalidate</li>
* <li>Pragma: no-cache</li>
* <li>Expires: 0</li>
* </ul>
*
* @param cacheControlCustomizer the {@link Customizer} to provide more options for
* the {@link CacheControlConfig}
* @return the {@link HeadersConfigurer} for additional customizations
* @throws Exception
*/
public HeadersConfigurer<H> cacheControl(Customizer<CacheControlConfig> cacheControlCustomizer) throws Exception {
cacheControlCustomizer.customize(cacheControl.enable());
return HeadersConfigurer.this;
}
public final class CacheControlConfig {
private CacheControlHeadersWriter writer;
@ -319,6 +381,21 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
return hsts.enable();
}
/**
* Allows customizing the {@link HstsHeaderWriter} which provides support for <a
* href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
* (HSTS)</a>.
*
* @param hstsCustomizer the {@link Customizer} to provide more options for
* the {@link HstsConfig}
* @return the {@link HeadersConfigurer} for additional customizations
* @throws Exception
*/
public HeadersConfigurer<H> httpStrictTransportSecurity(Customizer<HstsConfig> hstsCustomizer) throws Exception {
hstsCustomizer.customize(hsts.enable());
return HeadersConfigurer.this;
}
public final class HstsConfig {
private HstsHeaderWriter writer;
@ -440,6 +517,19 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> 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<H> frameOptions(Customizer<FrameOptionsConfig> frameOptionsCustomizer) throws Exception {
frameOptionsCustomizer.customize(frameOptions.enable());
return HeadersConfigurer.this;
}
public final class FrameOptionsConfig {
private XFrameOptionsHeaderWriter writer;
@ -516,6 +606,20 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
return hpkp.enable();
}
/**
* Allows customizing the {@link HpkpHeaderWriter} which provides support for <a
* href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
*
* @param hpkpCustomizer the {@link Customizer} to provide more options for
* the {@link HpkpConfig}
* @return the {@link HeadersConfigurer} for additional customizations
* @throws Exception
*/
public HeadersConfigurer<H> httpPublicKeyPinning(Customizer<HpkpConfig> hpkpCustomizer) throws Exception {
hpkpCustomizer.customize(hpkp.enable());
return HeadersConfigurer.this;
}
public final class HpkpConfig {
private HpkpHeaderWriter writer;
@ -713,12 +817,57 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
return contentSecurityPolicy;
}
/**
* <p>
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security Policy (CSP) Level 2</a>.
* </p>
*
* <p>
* Calling this method automatically enables (includes) the Content-Security-Policy header in the response
* using the supplied security policy directive(s).
* </p>
*
* <p>
* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which supports the writing
* of the two headers as detailed in the W3C Candidate Recommendation:
* </p>
* <ul>
* <li>Content-Security-Policy</li>
* <li>Content-Security-Policy-Report-Only</li>
* </ul>
*
* @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<H> contentSecurityPolicy(Customizer<ContentSecurityPolicyConfig> 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<H extends HttpSecurityBuilder<H>> extends
return this.referrerPolicy;
}
/**
* <p>
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
* </p>
*
* <p>
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
* of the header as detailed in the W3C Technical Report:
* </p>
* <ul>
* <li>Referrer-Policy</li>
* </ul>
*
* @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<H> referrerPolicy(Customizer<ReferrerPolicyConfig> 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<H extends HttpSecurityBuilder<H>> 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<H> and() {
return HeadersConfigurer.this;
}

View File

@ -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<H extends HttpSecurityBuilder<H>>
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<H> sessionFixation(Customizer<SessionFixationConfigurer> 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<H extends HttpSecurityBuilder<H>>
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<H> sessionConcurrency(Customizer<ConcurrencyControlConfigurer> 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<H extends HttpSecurityBuilder<H>>
*/
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

View File

@ -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<B extends HttpSecurityBuilder<B>> 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<B> authorizationCodeGrant(Customizer<AuthorizationCodeGrantConfigurer> authorizationCodeGrantCustomizer)
throws Exception {
authorizationCodeGrantCustomizer.customize(this.authorizationCodeGrantConfigurer);
return this;
}
/**
* Configuration options for the OAuth 2.0 Authorization Code Grant.
*/

View File

@ -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<B extends HttpSecurityBuilder<B>> 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<B> authorizationEndpoint(Customizer<AuthorizationEndpointConfig> 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<B extends HttpSecurityBuilder<B>> 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<B> tokenEndpoint(Customizer<TokenEndpointConfig> 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<B extends HttpSecurityBuilder<B>> 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<B> redirectionEndpoint(Customizer<RedirectionEndpointConfig> 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<B extends HttpSecurityBuilder<B>> 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<B> userInfoEndpoint(Customizer<UserInfoEndpointConfig> userInfoEndpointCustomizer)
throws Exception {
userInfoEndpointCustomizer.customize(this.userInfoEndpointConfig);
return this;
}
/**
* Configuration options for the Authorization Server's UserInfo Endpoint.
*/

View File

@ -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
* <li>{@link #accessDeniedHandler(AccessDeniedHandler)}</li> - customizes how access denied errors are handled
* <li>{@link #authenticationEntryPoint(AuthenticationEntryPoint)}</li> - customizes how authentication failures are handled
* <li>{@link #bearerTokenResolver(BearerTokenResolver)} - customizes how to resolve a bearer token from the request</li>
* <li>{@link #jwt()} - enables Jwt-encoded bearer token support</li>
* <li>{@link #jwt(Customizer)} - enables Jwt-encoded bearer token support</li>
* <li>{@link #opaqueToken(Customizer)} - enables opaque bearer token support</li>
* </ul>
*
* <p>
* When using {@link #jwt()}, either
* When using {@link #jwt(Customizer)}, either
*
* <ul>
* <li>
@ -83,7 +85,7 @@ import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSe
* </li>
* </ul>
*
* Also with {@link #jwt()} consider
* Also with {@link #jwt(Customizer)} consider
*
* <ul>
* <li>
@ -93,12 +95,12 @@ import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSe
* </ul>
*
* <p>
* 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
* </p>
*
* <h2>Security Filters</h2>
*
* 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:
*
* <ul>
* <li>{@link BearerTokenAuthenticationFilter}</li>
@ -180,6 +182,22 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
return this.jwtConfigurer;
}
/**
* Enables Jwt-encoded bearer token support.
*
* @param jwtCustomizer the {@link Customizer} to provide more options for
* the {@link JwtConfigurer}
* @return the {@link OAuth2ResourceServerConfigurer} for further customizations
* @throws Exception
*/
public OAuth2ResourceServerConfigurer<H> jwt(Customizer<JwtConfigurer> 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<H extends HttpSecurityBuilder<
return this.opaqueTokenConfigurer;
}
/**
* Enables opaque bearer token support.
*
* @param opaqueTokenCustomizer the {@link Customizer} to provide more options for
* the {@link OpaqueTokenConfigurer}
* @return the {@link OAuth2ResourceServerConfigurer} for further customizations
* @throws Exception
*/
public OAuth2ResourceServerConfigurer<H> opaqueToken(Customizer<OpaqueTokenConfigurer> 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);

View File

@ -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<H extends HttpSecurityBuilder<H>> exten
return attributeExchangeConfigurer;
}
/**
* Sets up OpenID attribute exchange for OpenIDs matching the specified pattern.
* The default pattern is &quot;.*&quot;, 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<H> attributeExchange(Customizer<AttributeExchangeConfigurer> 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<H extends HttpSecurityBuilder<H>> exten
* @author Rob Winch
*/
public final class AttributeExchangeConfigurer {
private final String identifier;
private String identifier;
private List<OpenIDAttribute> attributes = new ArrayList<>();
private List<AttributeConfigurer> attributeConfigurers = new ArrayList<>();
@ -395,6 +414,19 @@ public final class OpenIDLoginConfigurer<H extends HttpSecurityBuilder<H>> 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<H extends HttpSecurityBuilder<H>> exten
return attributeConfigurer;
}
/**
* Adds an {@link OpenIDAttribute} named &quot;default-attribute&quot;.
* 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<AttributeConfigurer> 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<H extends HttpSecurityBuilder<H>> 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<H extends HttpSecurityBuilder<H>> 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

View File

@ -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();
}
}
@RestController
static class PrincipalController {
@GetMapping("/")
String principal(@AuthenticationPrincipal String principal) {
return principal;
}
@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;
}
}
}

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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);
}
}
}

View File

@ -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")

View File

@ -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);

View File

@ -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()

View File

@ -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);

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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);

View File

@ -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
}
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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 <logout> 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())

View File

@ -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> T verifyBean(Class<T> beanClass) {
return verify(this.spring.getContext().getBean(beanClass));
}

View File

@ -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
}
}
}

View File

@ -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())

View File

@ -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 {

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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")

View File

@ -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);

View File

@ -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 extends Certificate> T loadCert(String location) {
try (InputStream is = new ClassPathResource(location).getInputStream()) {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");

View File

@ -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;
}
}
}

View File

@ -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<AuthenticationSuccessEvent> {
static List<AuthenticationSuccessEvent> 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 {

View File

@ -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

View File

@ -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("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", 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<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) 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("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", 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<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) 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
}
}
}

View File

@ -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")
);
}
----

View File

@ -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<OidcUserRequest, OidcUser> 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<OAuth2UserRequest, OAuth2User> 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<OidcUserRequest, OidcUser> oidcUserService() {

View File

@ -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.

View File

@ -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
</http>
----
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 <<oauth2resourceserver-j
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt()
.jwkSetUri("https://idp.example.com/.well-known/jwks.json");
.authorizeRequests(authorizeRequests ->
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<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
fsi.setPublishAuthorizationSuccess(true);
return fsi;
}
});
.authorizeRequests(authorizeRequests ->
authorizeRequests
.anyRequest().authenticated()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
public <O extends FilterSecurityInterceptor> O postProcess(
O fsi) {
fsi.setPublishAuthorizationSuccess(true);
return fsi;
}
})
);
}
----

View File

@ -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<OAuth2AuthorizationRequest> 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<OAuth2AuthorizationCodeGrantRequest> customAccessTokenResponseClient() {

View File

@ -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());
}
}

View File

@ -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())
...
}
}

View File

@ -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"))
);
}
}
----

View File

@ -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)
);
}
}
----

View File

@ -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 ->
...
)
...
----

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
*

View File

@ -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);