Skip to content

Resource Server JWK support #5476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/spring-security-config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies {
optional project(':spring-security-messaging')
optional project(':spring-security-oauth2-client')
optional project(':spring-security-oauth2-jose')
optional project(':spring-security-oauth2-resource-server')
optional project(':spring-security-openid')
optional project(':spring-security-web')
optional 'io.projectreactor:reactor-core'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 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.
Expand Down Expand Up @@ -128,7 +128,7 @@ public CsrfConfigurer<H> requireCsrfProtectionMatcher(
* </p>
*
* <p>
* The following will ensure CSRF protection ignores:
* For example, the following configuration will ensure CSRF protection ignores:
* </p>
* <ul>
* <li>Any GET, HEAD, TRACE, OPTIONS (this is the default)</li>
Expand All @@ -150,6 +150,35 @@ public CsrfConfigurer<H> ignoringAntMatchers(String... antPatterns) {
.and();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update header to 2018

/**
* <p>
* Allows specifying {@link HttpServletRequest}s that should not use CSRF Protection
* even if they match the {@link #requireCsrfProtectionMatcher(RequestMatcher)}.
* </p>
*
* <p>
* For example, the following configuration will ensure CSRF protection ignores:
* </p>
* <ul>
* <li>Any GET, HEAD, TRACE, OPTIONS (this is the default)</li>
* <li>We also explicitly state to ignore any request that has a "X-Requested-With: XMLHttpRequest" header</li>
* </ul>
*
* <pre>
* http
* .csrf()
* .ignoringRequestMatchers(request -> "XMLHttpRequest".equals(request.getHeader("X-Requested-With")))
* .and()
* ...
* </pre>
*
* @since 5.1
*/
public CsrfConfigurer<H> ignoringRequestMatchers(RequestMatcher... requestMatchers) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please create this as separate ticket and link to that ticket. Users will be interested to know about this separately. The separate commit can remain in this PR, but please make it a separate ticket and commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi - #5477

return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers)
.and();
}

@SuppressWarnings("unchecked")
@Override
public void configure(H http) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 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.
Expand All @@ -23,6 +23,7 @@
import org.springframework.security.web.access.AccessDeniedHandler;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update header to 2018

import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.access.RequestMatcherDelegatingAccessDeniedHandler;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
Expand Down Expand Up @@ -70,6 +71,8 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>

private LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> defaultEntryPointMappings = new LinkedHashMap<>();

private LinkedHashMap<RequestMatcher, AccessDeniedHandler> defaultDeniedHandlerMappings = new LinkedHashMap<>();

/**
* Creates a new instance
* @see HttpSecurity#exceptionHandling()
Expand Down Expand Up @@ -104,6 +107,26 @@ public ExceptionHandlingConfigurer<H> accessDeniedHandler(
return this;
}

/**
* Sets a default {@link AccessDeniedHandler} to be used which prefers being
* invoked for the provided {@link RequestMatcher}. If only a single default
* {@link AccessDeniedHandler} is specified, it will be what is used for the
* default {@link AccessDeniedHandler}. If multiple default
* {@link AccessDeniedHandler} instances are configured, then a
* {@link RequestMatcherDelegatingAccessDeniedHandler} will be used.
*
* @param deniedHandler the {@link AccessDeniedHandler} to use
* @param preferredMatcher the {@link RequestMatcher} for this default
* {@link AccessDeniedHandler}
* @return the {@link ExceptionHandlingConfigurer} for further customizations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @since tag

* @since 5.1
*/
public ExceptionHandlingConfigurer<H> defaultAccessDeniedHandlerFor(
AccessDeniedHandler deniedHandler, RequestMatcher preferredMatcher) {
this.defaultDeniedHandlerMappings.put(preferredMatcher, deniedHandler);
return this;
}

/**
* Sets the {@link AuthenticationEntryPoint} to be used.
*
Expand Down Expand Up @@ -169,13 +192,27 @@ public void configure(H http) throws Exception {
AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
entryPoint, getRequestCache(http));
if (accessDeniedHandler != null) {
exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler);
}
AccessDeniedHandler deniedHandler = getAccessDeniedHandler(http);
exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
http.addFilter(exceptionTranslationFilter);
}

/**
* Gets the {@link AccessDeniedHandler} according to the rules specified by
* {@link #accessDeniedHandler(AccessDeniedHandler)}
* @param http the {@link HttpSecurity} used to look up shared
* {@link AccessDeniedHandler}
* @return the {@link AccessDeniedHandler} to use
*/
AccessDeniedHandler getAccessDeniedHandler(H http) {
AccessDeniedHandler deniedHandler = this.accessDeniedHandler;
if (deniedHandler == null) {
deniedHandler = createDefaultDeniedHandler(http);
}
return deniedHandler;
}

/**
* Gets the {@link AuthenticationEntryPoint} according to the rules specified by
* {@link #authenticationEntryPoint(AuthenticationEntryPoint)}
Expand All @@ -191,16 +228,28 @@ AuthenticationEntryPoint getAuthenticationEntryPoint(H http) {
return entryPoint;
}

private AccessDeniedHandler createDefaultDeniedHandler(H http) {
if (this.defaultDeniedHandlerMappings.isEmpty()) {
return new AccessDeniedHandlerImpl();
}
if (this.defaultDeniedHandlerMappings.size() == 1) {
return this.defaultDeniedHandlerMappings.values().iterator().next();
}
return new RequestMatcherDelegatingAccessDeniedHandler(
this.defaultDeniedHandlerMappings,
new AccessDeniedHandlerImpl());
}

private AuthenticationEntryPoint createDefaultEntryPoint(H http) {
if (defaultEntryPointMappings.isEmpty()) {
if (this.defaultEntryPointMappings.isEmpty()) {
return new Http403ForbiddenEntryPoint();
}
if (defaultEntryPointMappings.size() == 1) {
return defaultEntryPointMappings.values().iterator().next();
if (this.defaultEntryPointMappings.size() == 1) {
return this.defaultEntryPointMappings.values().iterator().next();
}
DelegatingAuthenticationEntryPoint entryPoint = new DelegatingAuthenticationEntryPoint(
defaultEntryPointMappings);
entryPoint.setDefaultEntryPoint(defaultEntryPointMappings.values().iterator()
this.defaultEntryPointMappings);
entryPoint.setDefaultEntryPoint(this.defaultEntryPointMappings.values().iterator()
.next());
return entryPoint;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
Expand All @@ -18,7 +18,6 @@
import java.util.ArrayList;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update header to 2018

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. For future reference, am I making the correct inference that whenever we touch a file, we update its license header? (This makes sense to me, I just don't want to misunderstand.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

Expand Down Expand Up @@ -105,7 +104,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
private Integer maximumSessions;
private String expiredUrl;
private boolean maxSessionsPreventsLogin;
private SessionCreationPolicy sessionPolicy = SessionCreationPolicy.IF_REQUIRED;
private SessionCreationPolicy sessionPolicy;
private boolean enableSessionUrlRewriting;
private String invalidSessionUrl;
private String sessionAuthenticationErrorUrl;
Expand Down Expand Up @@ -549,7 +548,14 @@ AuthenticationFailureHandler getSessionAuthenticationFailureHandler() {
* @return the {@link SessionCreationPolicy}
*/
SessionCreationPolicy getSessionCreationPolicy() {
return this.sessionPolicy;
if (this.sessionPolicy != null) {
return this.sessionPolicy;
}

SessionCreationPolicy sessionPolicy =
getBuilder().getSharedObject(SessionCreationPolicy.class);
return sessionPolicy == null ?
SessionCreationPolicy.IF_REQUIRED : sessionPolicy;
}

/**
Expand All @@ -558,16 +564,18 @@ SessionCreationPolicy getSessionCreationPolicy() {
* @return true if the {@link SessionCreationPolicy} allows session creation
*/
private boolean isAllowSessionCreation() {
return SessionCreationPolicy.ALWAYS == this.sessionPolicy
|| SessionCreationPolicy.IF_REQUIRED == this.sessionPolicy;
SessionCreationPolicy sessionPolicy = getSessionCreationPolicy();
return SessionCreationPolicy.ALWAYS == sessionPolicy
|| SessionCreationPolicy.IF_REQUIRED == sessionPolicy;
}

/**
* Returns true if the {@link SessionCreationPolicy} is stateless
* @return
*/
private boolean isStateless() {
return SessionCreationPolicy.STATELESS == this.sessionPolicy;
SessionCreationPolicy sessionPolicy = getSessionCreationPolicy();
return SessionCreationPolicy.STATELESS == sessionPolicy;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2ClientConfigurer;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;

/**
* An {@link AbstractHttpConfigurer} that provides support for the
Expand All @@ -40,6 +41,8 @@ public final class OAuth2Configurer<B extends HttpSecurityBuilder<B>>

private OAuth2ClientConfigurer<B> clientConfigurer;

private OAuth2ResourceServerConfigurer<B> resourceServerConfigurer;

/**
* Returns the {@link OAuth2ClientConfigurer} for configuring OAuth 2.0 Client support.
*
Expand All @@ -52,23 +55,49 @@ public OAuth2ClientConfigurer<B> client() {
return this.clientConfigurer;
}

/**
* Returns the {@link OAuth2ResourceServerConfigurer} for configuring OAuth 2.0 Resource Server support.
*
* @return the {@link OAuth2ResourceServerConfigurer}
*/
public OAuth2ResourceServerConfigurer<B> resourceServer() {
if (this.resourceServerConfigurer == null) {
this.initResourceServerConfigurer();
}
return this.resourceServerConfigurer;
}

@Override
public void init(B builder) throws Exception {
if (this.clientConfigurer != null) {
this.clientConfigurer.init(builder);
}

if (this.resourceServerConfigurer != null) {
this.resourceServerConfigurer.init(builder);
}
}

@Override
public void configure(B builder) throws Exception {
if (this.clientConfigurer != null) {
this.clientConfigurer.configure(builder);
}

if (this.resourceServerConfigurer != null) {
this.resourceServerConfigurer.configure(builder);
}
}

private void initClientConfigurer() {
this.clientConfigurer = new OAuth2ClientConfigurer<>();
this.clientConfigurer.setBuilder(this.getBuilder());
this.clientConfigurer.addObjectPostProcessor(this.objectPostProcessor);
}

private void initResourceServerConfigurer() {
this.resourceServerConfigurer = new OAuth2ResourceServerConfigurer<>();
this.resourceServerConfigurer.setBuilder(this.getBuilder());
this.resourceServerConfigurer.addObjectPostProcessor(this.objectPostProcessor);
}
}
Loading