mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 09:12:14 +00:00
DSL nested builder for HTTP security
DSL nested builder for HTTP security Fixes gh-5557
This commit is contained in:
commit
ea54d9014d
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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 ".*", 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 "default-attribute".
|
||||
* The name can by updated using {@link AttributeConfigurer#name(String)}.
|
||||
*
|
||||
* @param attributeCustomizer the {@link Customizer} to provide more options for
|
||||
* the {@link AttributeConfigurer}
|
||||
* @return a {@link AttributeExchangeConfigurer} for further customizations
|
||||
* @throws Exception
|
||||
*/
|
||||
public AttributeExchangeConfigurer attribute(Customizer<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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
);
|
||||
}
|
||||
----
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
----
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
...
|
||||
}
|
||||
}
|
||||
|
@ -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"))
|
||||
);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
|
@ -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 ->
|
||||
...
|
||||
)
|
||||
...
|
||||
----
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user