Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 69a13dfcd4 | |||
| 89afd4c487 | |||
| 35e769d90b | |||
| d9e1906281 | |||
| e6f28b9c02 | |||
| 65230b8ee2 | |||
| 57d94ce816 | |||
| c967d6569d | |||
| 10f7a968c1 | |||
| 344bad34be | |||
| 9792e2a0fa | |||
| 44508df940 | |||
| 35ac1dd71e | |||
| 1460d53b2f | |||
| 040a28a8c9 | |||
| 0ae6e6e767 | |||
| 2f25c03609 | |||
| 7271499e74 | |||
| f2fc2a593f | |||
| f491cc8938 | |||
| 22a39545b9 | |||
| 36d57b597e | |||
| 02c6b04320 | |||
| 2c3522e290 | |||
| 01e37feb0d | |||
| 6403cba2f5 | |||
| d655deb718 | |||
| 6156f29c3b | |||
| 25363ac13e | |||
| 15d902322f | |||
| 070b67a9a1 | |||
| 304ef2302c | |||
| a09f6e15ad | |||
| 7e0302be5c | |||
| 7554ee8fec | |||
| 893b651aea | |||
| ca353d6781 | |||
| a763382c3e | |||
| 60595f2801 | |||
| ba810e468f | |||
| 40dfe8f259 | |||
| b448954f43 | |||
| b0c7d7703b | |||
| 5bc0537f1b | |||
| 355bf8ddee | |||
| 05585a5f13 | |||
| 00d350608a | |||
| 906c520fa0 | |||
| ca19601f8b | |||
| bdd4d05ce2 | |||
| 0eec932917 | |||
| af5c1761e8 | |||
| 491989c692 | |||
| 731069a69a | |||
| 47b8860681 | |||
| 828cac8889 | |||
| aefd2d497c | |||
| 775bf91c77 | |||
| 2bf7a5ae80 | |||
| c495ff8759 | |||
| b7a12e1b80 | |||
| 670d10dadd | |||
| 72db6a20c9 | |||
| 00f4033b9b | |||
| ddb59d439f | |||
| e4a76b0ec9 | |||
| 78e8507af7 |
@@ -0,0 +1,6 @@
|
||||
# Use sdkman to run "sdk env" to initialize with correct JDK version
|
||||
# Enable auto-env through the sdkman_auto_env config
|
||||
# See https://sdkman.io/usage#config
|
||||
# A summary is to add the following to ~/.sdkman/etc/config
|
||||
# sdkman_auto_env=true
|
||||
java=11.0.14-tem
|
||||
@@ -106,6 +106,8 @@ subprojects {
|
||||
}
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
options.compilerArgs.add("-parameters")
|
||||
options.release = 8
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ dependencies {
|
||||
implementation localGroovy()
|
||||
|
||||
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
|
||||
implementation 'io.projectreactor:reactor-core:3.4.11'
|
||||
implementation 'io.projectreactor:reactor-core:3.4.17'
|
||||
implementation 'gradle.plugin.org.gretty:gretty:3.0.1'
|
||||
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
|
||||
implementation 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
|
||||
|
||||
@@ -40,9 +40,9 @@ import org.jasig.cas.client.authentication.AttributePrincipal;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CasJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
|
||||
+1
-1
@@ -37,9 +37,9 @@ import org.jasig.cas.client.proxy.ProxyRetriever;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CasJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
|
||||
+1
-1
@@ -47,9 +47,9 @@ import org.springframework.security.core.userdetails.UserDetails;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CasJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
|
||||
@@ -19,8 +19,8 @@ package org.springframework.security.config;
|
||||
/**
|
||||
* Callback interface that accepts a single input argument and returns no result.
|
||||
*
|
||||
* @author Eleftheria Stein
|
||||
* @param <T> the type of the input to the operation
|
||||
* @author Eleftheria Stein
|
||||
* @since 5.2
|
||||
*/
|
||||
@FunctionalInterface
|
||||
|
||||
+1
-1
@@ -27,8 +27,8 @@ import org.springframework.security.config.annotation.authentication.builders.Au
|
||||
* {@link AuthenticationConfiguration} to configure the global
|
||||
* {@link AuthenticationManagerBuilder}.
|
||||
*
|
||||
* @since 5.0
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
@Order(100)
|
||||
public abstract class GlobalAuthenticationConfigurerAdapter
|
||||
|
||||
+2
-2
@@ -30,10 +30,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
* class is not intended to be imported manually rather it is imported automatically when
|
||||
* using {@link EnableWebSecurity} or {@link EnableGlobalMethodSecurity}.
|
||||
*
|
||||
* @see EnableWebSecurity
|
||||
* @see EnableGlobalMethodSecurity
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @see EnableWebSecurity
|
||||
* @see EnableGlobalMethodSecurity
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
|
||||
+53
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.access.PermissionEvaluator;
|
||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||
import org.springframework.security.config.annotation.SecurityBuilder;
|
||||
@@ -47,9 +49,12 @@ import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.AuthorizationManagerWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.security.web.access.intercept.AuthorizationFilter;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.debug.DebugFilter;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
@@ -57,7 +62,9 @@ import org.springframework.security.web.firewall.RequestRejectedHandler;
|
||||
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
|
||||
/**
|
||||
@@ -81,7 +88,7 @@ import org.springframework.web.filter.DelegatingFilterProxy;
|
||||
* @see WebSecurityConfiguration
|
||||
*/
|
||||
public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity>
|
||||
implements SecurityBuilder<Filter>, ApplicationContextAware {
|
||||
implements SecurityBuilder<Filter>, ApplicationContextAware, ServletContextAware {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -108,6 +115,8 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
private Runnable postBuildAction = () -> {
|
||||
};
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
|
||||
@@ -252,6 +261,8 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
* {@link WebSecurityConfigurerAdapter}.
|
||||
* @param securityInterceptor the {@link FilterSecurityInterceptor} to use
|
||||
* @return the {@link WebSecurity} for further customizations
|
||||
* @deprecated Use {@link #privilegeEvaluator(WebInvocationPrivilegeEvaluator)}
|
||||
* instead
|
||||
*/
|
||||
public WebSecurity securityInterceptor(FilterSecurityInterceptor securityInterceptor) {
|
||||
this.filterSecurityInterceptor = securityInterceptor;
|
||||
@@ -278,11 +289,24 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
+ ".addSecurityFilterChainBuilder directly");
|
||||
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
|
||||
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
|
||||
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries = new ArrayList<>();
|
||||
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
|
||||
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
|
||||
WebSecurity.this.logger.warn("You are asking Spring Security to ignore " + ignoredRequest
|
||||
+ ". This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.");
|
||||
SecurityFilterChain securityFilterChain = new DefaultSecurityFilterChain(ignoredRequest);
|
||||
securityFilterChains.add(securityFilterChain);
|
||||
requestMatcherPrivilegeEvaluatorsEntries
|
||||
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
|
||||
}
|
||||
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
|
||||
securityFilterChains.add(securityFilterChainBuilder.build());
|
||||
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
|
||||
securityFilterChains.add(securityFilterChain);
|
||||
requestMatcherPrivilegeEvaluatorsEntries
|
||||
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
|
||||
}
|
||||
if (this.privilegeEvaluator == null) {
|
||||
this.privilegeEvaluator = new RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
|
||||
requestMatcherPrivilegeEvaluatorsEntries);
|
||||
}
|
||||
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
|
||||
if (this.httpFirewall != null) {
|
||||
@@ -306,6 +330,26 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
return result;
|
||||
}
|
||||
|
||||
private RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> getRequestMatcherPrivilegeEvaluatorsEntry(
|
||||
SecurityFilterChain securityFilterChain) {
|
||||
List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = new ArrayList<>();
|
||||
for (Filter filter : securityFilterChain.getFilters()) {
|
||||
if (filter instanceof FilterSecurityInterceptor) {
|
||||
DefaultWebInvocationPrivilegeEvaluator defaultWebInvocationPrivilegeEvaluator = new DefaultWebInvocationPrivilegeEvaluator(
|
||||
(FilterSecurityInterceptor) filter);
|
||||
defaultWebInvocationPrivilegeEvaluator.setServletContext(this.servletContext);
|
||||
privilegeEvaluators.add(defaultWebInvocationPrivilegeEvaluator);
|
||||
continue;
|
||||
}
|
||||
if (filter instanceof AuthorizationFilter) {
|
||||
AuthorizationManager<HttpServletRequest> authorizationManager = ((AuthorizationFilter) filter)
|
||||
.getAuthorizationManager();
|
||||
privilegeEvaluators.add(new AuthorizationManagerWebInvocationPrivilegeEvaluator(authorizationManager));
|
||||
}
|
||||
}
|
||||
return new RequestMatcherEntry<>(securityFilterChain::matches, privilegeEvaluators);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.defaultWebSecurityExpressionHandler.setApplicationContext(applicationContext);
|
||||
@@ -333,6 +377,11 @@ public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link IgnoredRequestConfigurer} that allows optionally configuring the
|
||||
* {@link MvcRequestMatcher#setMethod(HttpMethod)}
|
||||
|
||||
+4
-4
@@ -60,11 +60,11 @@ import org.springframework.util.Assert;
|
||||
* {@link WebSecurityConfigurer} and exposing it as a {@link Configuration}. This
|
||||
* configuration is imported when using {@link EnableWebSecurity}.
|
||||
*
|
||||
* @see EnableWebSecurity
|
||||
* @see WebSecurity
|
||||
* @author Rob Winch
|
||||
* @author Keesun Baik
|
||||
* @since 3.2
|
||||
* @see EnableWebSecurity
|
||||
* @see WebSecurity
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
|
||||
@@ -128,8 +128,8 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link WebInvocationPrivilegeEvaluator} that is necessary for the JSP
|
||||
* tag support.
|
||||
* Creates the {@link WebInvocationPrivilegeEvaluator} that is necessary to evaluate
|
||||
* privileges for a given web URI
|
||||
* @return the {@link WebInvocationPrivilegeEvaluator}
|
||||
*/
|
||||
@Bean
|
||||
|
||||
+1
-1
@@ -87,8 +87,8 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
* org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyClassThatExtendsAbstractHttpConfigurer, sample.OtherThatExtendsAbstractHttpConfigurer
|
||||
* </pre>
|
||||
*
|
||||
* @see EnableWebSecurity
|
||||
* @author Rob Winch
|
||||
* @see EnableWebSecurity
|
||||
*/
|
||||
@Order(100)
|
||||
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
|
||||
|
||||
+1
-1
@@ -490,8 +490,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
||||
* @return the {@link FeaturePolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if policyDirectives is {@code null} or empty
|
||||
* @since 5.1
|
||||
* @see FeaturePolicyHeaderWriter
|
||||
* @deprecated Use {@link #permissionsPolicy(Customizer)} instead.
|
||||
* @seeObjectPostProcessorConfiguration FeaturePolicyHeaderWriter
|
||||
*/
|
||||
@Deprecated
|
||||
public FeaturePolicyConfig featurePolicy(String policyDirectives) {
|
||||
|
||||
+4
-4
@@ -49,15 +49,15 @@ import org.springframework.util.Assert;
|
||||
* <li>{@link ClientRegistrationRepository}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 5.0
|
||||
* @see OAuth2AuthorizationRequestRedirectFilter
|
||||
* @see ClientRegistrationRepository
|
||||
* @deprecated It is not recommended to use the implicit flow due to the inherent risks of
|
||||
* returning access tokens in an HTTP redirect without any confirmation that it has been
|
||||
* received by the client. See reference
|
||||
* <a target="_blank" href="https://oauth.net/2/grant-types/implicit/">OAuth 2.0 Implicit
|
||||
* Grant</a>.
|
||||
* @author Joe Grandja
|
||||
* @since 5.0
|
||||
* @see OAuth2AuthorizationRequestRedirectFilter
|
||||
* @see ClientRegistrationRepository
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ImplicitGrantConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
|
||||
+1
-1
@@ -683,10 +683,10 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
/**
|
||||
* Sets a custom {@link OAuth2User} type and associates it to the provided client
|
||||
* {@link ClientRegistration#getRegistrationId() registration identifier}.
|
||||
* @deprecated See {@link CustomUserTypesOAuth2UserService} for alternative usage.
|
||||
* @param customUserType a custom {@link OAuth2User} type
|
||||
* @param clientRegistrationId the client registration identifier
|
||||
* @return the {@link UserInfoEndpointConfig} for further configuration
|
||||
* @deprecated See {@link CustomUserTypesOAuth2UserService} for alternative usage.
|
||||
*/
|
||||
@Deprecated
|
||||
public UserInfoEndpointConfig customUserType(Class<? extends OAuth2User> customUserType,
|
||||
|
||||
+1
-2
@@ -276,8 +276,7 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
|
||||
if (version != null) {
|
||||
return version;
|
||||
}
|
||||
return Version.class.getModule().getDescriptor().version().map(Object::toString)
|
||||
.orElseThrow(() -> new IllegalStateException("cannot determine OpenSAML version"));
|
||||
return Version.getVersion();
|
||||
}
|
||||
|
||||
private void registerDefaultAuthenticationProvider(B http) {
|
||||
|
||||
+1
-1
@@ -37,9 +37,9 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
* {@link AuthenticationPrincipalArgumentResolver} as a
|
||||
* {@link HandlerMethodArgumentResolver}.
|
||||
*
|
||||
* @deprecated This is applied internally using SpringWebMvcImportSelector
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @deprecated This is applied internally using SpringWebMvcImportSelector
|
||||
*/
|
||||
@Deprecated
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
||||
+1
-1
@@ -79,8 +79,8 @@ import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsSe
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @since 4.0
|
||||
* @author Rob Winch
|
||||
* @since 4.0
|
||||
*/
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 100)
|
||||
@Import(ObjectPostProcessorConfiguration.class)
|
||||
|
||||
+191
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
@@ -61,7 +62,7 @@ import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@@ -83,6 +84,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
* @author Rob Winch
|
||||
* @author Joe Grandja
|
||||
* @author Evgeniy Cheban
|
||||
* @author Marcus Da Coregio
|
||||
*/
|
||||
public class WebSecurityConfigurationTests {
|
||||
|
||||
@@ -218,10 +220,10 @@ public class WebSecurityConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadConfigWhenDefaultWebInvocationPrivilegeEvaluatorThenDefaultIsRegistered() {
|
||||
public void loadConfigWhenDefaultWebInvocationPrivilegeEvaluatorThenRequestMatcherIsRegistered() {
|
||||
this.spring.register(WebInvocationPrivilegeEvaluatorDefaultsConfig.class).autowire();
|
||||
assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
|
||||
.isInstanceOf(DefaultWebInvocationPrivilegeEvaluator.class);
|
||||
.isInstanceOf(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -229,7 +231,7 @@ public class WebSecurityConfigurationTests {
|
||||
this.spring.register(AuthorizeRequestsFilterChainConfig.class).autowire();
|
||||
|
||||
assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
|
||||
.isInstanceOf(DefaultWebInvocationPrivilegeEvaluator.class);
|
||||
.isInstanceOf(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.class);
|
||||
}
|
||||
|
||||
// SEC-2303
|
||||
@@ -375,6 +377,69 @@ public class WebSecurityConfigurationTests {
|
||||
assertThat(filterChains.get(1).matches(request)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadConfigWhenTwoSecurityFilterChainsThenRequestMatcherDelegatingWebInvocationPrivilegeEvaluator() {
|
||||
this.spring.register(TwoSecurityFilterChainConfig.class).autowire();
|
||||
assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
|
||||
.isInstanceOf(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadConfigWhenTwoSecurityFilterChainDebugThenRequestMatcherDelegatingWebInvocationPrivilegeEvaluator() {
|
||||
this.spring.register(TwoSecurityFilterChainConfig.class).autowire();
|
||||
assertThat(this.spring.getContext().getBean(WebInvocationPrivilegeEvaluator.class))
|
||||
.isInstanceOf(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.class);
|
||||
}
|
||||
|
||||
// gh-10554
|
||||
@Test
|
||||
public void loadConfigWhenMultipleSecurityFilterChainsThenWebInvocationPrivilegeEvaluatorApplySecurity() {
|
||||
this.spring.register(MultipleSecurityFilterChainConfig.class).autowire();
|
||||
WebInvocationPrivilegeEvaluator privilegeEvaluator = this.spring.getContext()
|
||||
.getBean(WebInvocationPrivilegeEvaluator.class);
|
||||
assertUserPermissions(privilegeEvaluator);
|
||||
assertAdminPermissions(privilegeEvaluator);
|
||||
assertAnotherUserPermission(privilegeEvaluator);
|
||||
}
|
||||
|
||||
// gh-10554
|
||||
@Test
|
||||
public void loadConfigWhenMultipleSecurityFilterChainAndIgnoringThenWebInvocationPrivilegeEvaluatorAcceptsNullAuthenticationOnIgnored() {
|
||||
this.spring.register(MultipleSecurityFilterChainIgnoringConfig.class).autowire();
|
||||
WebInvocationPrivilegeEvaluator privilegeEvaluator = this.spring.getContext()
|
||||
.getBean(WebInvocationPrivilegeEvaluator.class);
|
||||
assertUserPermissions(privilegeEvaluator);
|
||||
assertAdminPermissions(privilegeEvaluator);
|
||||
assertAnotherUserPermission(privilegeEvaluator);
|
||||
// null authentication
|
||||
assertThat(privilegeEvaluator.isAllowed("/user", null)).isFalse();
|
||||
assertThat(privilegeEvaluator.isAllowed("/admin", null)).isFalse();
|
||||
assertThat(privilegeEvaluator.isAllowed("/another", null)).isFalse();
|
||||
assertThat(privilegeEvaluator.isAllowed("/ignoring1", null)).isTrue();
|
||||
assertThat(privilegeEvaluator.isAllowed("/ignoring1/child", null)).isTrue();
|
||||
}
|
||||
|
||||
private void assertAnotherUserPermission(WebInvocationPrivilegeEvaluator privilegeEvaluator) {
|
||||
Authentication anotherUser = new TestingAuthenticationToken("anotherUser", "password", "ROLE_ANOTHER");
|
||||
assertThat(privilegeEvaluator.isAllowed("/user", anotherUser)).isFalse();
|
||||
assertThat(privilegeEvaluator.isAllowed("/admin", anotherUser)).isFalse();
|
||||
assertThat(privilegeEvaluator.isAllowed("/another", anotherUser)).isTrue();
|
||||
}
|
||||
|
||||
private void assertAdminPermissions(WebInvocationPrivilegeEvaluator privilegeEvaluator) {
|
||||
Authentication admin = new TestingAuthenticationToken("admin", "password", "ROLE_ADMIN");
|
||||
assertThat(privilegeEvaluator.isAllowed("/user", admin)).isFalse();
|
||||
assertThat(privilegeEvaluator.isAllowed("/admin", admin)).isTrue();
|
||||
assertThat(privilegeEvaluator.isAllowed("/another", admin)).isTrue();
|
||||
}
|
||||
|
||||
private void assertUserPermissions(WebInvocationPrivilegeEvaluator privilegeEvaluator) {
|
||||
Authentication user = new TestingAuthenticationToken("user", "password", "ROLE_USER");
|
||||
assertThat(privilegeEvaluator.isAllowed("/user", user)).isTrue();
|
||||
assertThat(privilegeEvaluator.isAllowed("/admin", user)).isFalse();
|
||||
assertThat(privilegeEvaluator.isAllowed("/another", user)).isTrue();
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Import(AuthenticationTestConfiguration.class)
|
||||
static class SortedWebSecurityConfigurerAdaptersConfig {
|
||||
@@ -1008,4 +1073,125 @@ public class WebSecurityConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class TwoSecurityFilterChainConfig {
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.requestMatchers((requests) -> requests.antMatchers("/path1/**"))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().authenticated());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
public SecurityFilterChain permitAll(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity(debug = true)
|
||||
static class TwoSecurityFilterChainDebugConfig {
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.requestMatchers((requests) -> requests.antMatchers("/path1/**"))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().authenticated());
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
public SecurityFilterChain permitAll(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Import(AuthenticationTestConfiguration.class)
|
||||
static class MultipleSecurityFilterChainConfig {
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.requestMatchers((requests) -> requests.antMatchers("/user"))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().hasRole("USER"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
|
||||
public SecurityFilterChain path1(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.requestMatchers((requests) -> requests.antMatchers("/admin"))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
public SecurityFilterChain permitAll(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Import(AuthenticationTestConfiguration.class)
|
||||
static class MultipleSecurityFilterChainIgnoringConfig {
|
||||
|
||||
@Bean
|
||||
public WebSecurityCustomizer webSecurityCustomizer() {
|
||||
return (web) -> web.ignoring().antMatchers("/ignoring1/**");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public SecurityFilterChain notAuthorized(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.requestMatchers((requests) -> requests.antMatchers("/user"))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().hasRole("USER"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
|
||||
public SecurityFilterChain admin(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.requestMatchers((requests) -> requests.antMatchers("/admin"))
|
||||
.authorizeRequests((requests) -> requests.anyRequest().hasRole("ADMIN"));
|
||||
// @formatter:on
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
public SecurityFilterChain permitAll(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().permitAll());
|
||||
return http.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-7
@@ -21,11 +21,13 @@ import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import sun.security.x509.X500Name;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -239,12 +241,8 @@ public class NamespaceHttpX509Tests {
|
||||
}
|
||||
|
||||
private String extractCommonName(X509Certificate certificate) {
|
||||
try {
|
||||
return ((X500Name) certificate.getSubjectDN()).getCommonName();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
X500Principal principal = certificate.getSubjectX500Principal();
|
||||
return new X500Name(principal.getName()).getRDNs(BCStyle.CN)[0].getFirst().getValue().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ public class Saml2LoginConfigurerTests {
|
||||
public void authenticateWithInvalidDeflatedSAMLResponseThenFailureHandlerUses() throws Exception {
|
||||
this.spring.register(CustomAuthenticationFailureHandler.class).autowire();
|
||||
byte[] invalidDeflated = "invalid".getBytes();
|
||||
String encoded = Saml2Utils.samlEncode(invalidDeflated);
|
||||
String encoded = Saml2Utils.samlEncodeNotRfc2045(invalidDeflated);
|
||||
MockHttpServletRequestBuilder request = get("/login/saml2/sso/registration-id").queryParam("SAMLResponse",
|
||||
encoded);
|
||||
this.mvc.perform(request);
|
||||
|
||||
+1
-1
@@ -40,9 +40,9 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
* <i>Note: This class will save full class name into a property called @class</i>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CoreJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, isGetterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
|
||||
+1
-1
@@ -36,8 +36,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
* called @class</i> <i>The cause and stackTrace are ignored in the serialization.</i>
|
||||
*
|
||||
* @author Yannick Lombardi
|
||||
* @see CoreJackson2Module
|
||||
* @since 5.0
|
||||
* @see CoreJackson2Module
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true, value = { "cause", "stackTrace" })
|
||||
|
||||
@@ -44,8 +44,8 @@ import org.springframework.security.core.userdetails.User;
|
||||
* of all security modules.</b>
|
||||
*
|
||||
* @author Jitendra Singh.
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
* @see SecurityJackson2Modules
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CoreJackson2Module extends SimpleModule {
|
||||
|
||||
+1
-1
@@ -47,9 +47,9 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
* called @class</i>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CoreJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
|
||||
+1
-1
@@ -32,9 +32,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CoreJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
|
||||
@@ -32,10 +32,10 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
* </pre>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0.2
|
||||
* @see UnmodifiableListDeserializer
|
||||
* @see CoreJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 5.0.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonDeserialize(using = UnmodifiableListDeserializer.class)
|
||||
|
||||
@@ -32,10 +32,10 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see UnmodifiableSetDeserializer
|
||||
* @see CoreJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonDeserialize(using = UnmodifiableSetDeserializer.class)
|
||||
|
||||
@@ -37,10 +37,10 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see UserDeserializer
|
||||
* @see CoreJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonDeserialize(using = UserDeserializer.class)
|
||||
|
||||
+1
-1
@@ -39,9 +39,9 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see CoreJackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
|
||||
+14
-14
@@ -8,14 +8,14 @@ javaPlatform {
|
||||
|
||||
dependencies {
|
||||
api platform("org.springframework:spring-framework-bom:$springFrameworkVersion")
|
||||
api platform("io.projectreactor:reactor-bom:2020.0.12")
|
||||
api platform("io.rsocket:rsocket-bom:1.1.1")
|
||||
api platform("org.springframework.data:spring-data-bom:2021.0.6")
|
||||
api platform("io.projectreactor:reactor-bom:2020.0.18")
|
||||
api platform("io.rsocket:rsocket-bom:1.1.2")
|
||||
api platform("org.springframework.data:spring-data-bom:2021.0.10")
|
||||
api platform("org.jetbrains.kotlin:kotlin-bom:$kotlinVersion")
|
||||
api platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.2")
|
||||
api platform("com.fasterxml.jackson:jackson-bom:2.12.5")
|
||||
api platform("com.fasterxml.jackson:jackson-bom:2.12.6.20220326")
|
||||
constraints {
|
||||
api "ch.qos.logback:logback-classic:1.2.6"
|
||||
api "ch.qos.logback:logback-classic:1.2.11"
|
||||
api "com.google.inject:guice:3.0"
|
||||
api "com.nimbusds:nimbus-jose-jwt:9.10.1"
|
||||
api "com.nimbusds:oauth2-oidc-sdk:9.9.1"
|
||||
@@ -49,12 +49,12 @@ dependencies {
|
||||
api "org.assertj:assertj-core:3.19.0"
|
||||
api "org.bouncycastle:bcpkix-jdk15on:1.68"
|
||||
api "org.bouncycastle:bcprov-jdk15on:1.68"
|
||||
api "org.eclipse.jetty:jetty-server:9.4.44.v20210927"
|
||||
api "org.eclipse.jetty:jetty-servlet:9.4.44.v20210927"
|
||||
api "org.eclipse.jetty:jetty-server:9.4.46.v20220331"
|
||||
api "org.eclipse.jetty:jetty-servlet:9.4.46.v20220331"
|
||||
api "org.eclipse.persistence:javax.persistence:2.2.1"
|
||||
api "org.hibernate:hibernate-entitymanager:5.4.32.Final"
|
||||
api "org.hsqldb:hsqldb:2.6.0"
|
||||
api "org.jasig.cas.client:cas-client-core:3.6.2"
|
||||
api "org.hibernate:hibernate-entitymanager:5.4.33"
|
||||
api "org.hsqldb:hsqldb:2.6.1"
|
||||
api "org.jasig.cas.client:cas-client-core:3.6.4"
|
||||
api "org.mockito:mockito-core:3.9.0"
|
||||
api "org.openid4java:openid4java-nodeps:0.9.6"
|
||||
api "org.opensaml:opensaml-core:$openSamlVersion"
|
||||
@@ -71,10 +71,10 @@ dependencies {
|
||||
api "org.seleniumhq.selenium:selenium-java:3.141.59"
|
||||
api "org.seleniumhq.selenium:selenium-support:3.141.59"
|
||||
api "org.skyscreamer:jsonassert:1.5.0"
|
||||
api "org.slf4j:jcl-over-slf4j:1.7.32"
|
||||
api "org.slf4j:log4j-over-slf4j:1.7.32"
|
||||
api "org.slf4j:slf4j-api:1.7.32"
|
||||
api "org.springframework.ldap:spring-ldap-core:2.3.4.RELEASE"
|
||||
api "org.slf4j:jcl-over-slf4j:1.7.36"
|
||||
api "org.slf4j:log4j-over-slf4j:1.7.36"
|
||||
api "org.slf4j:slf4j-api:1.7.36"
|
||||
api "org.springframework.ldap:spring-ldap-core:2.3.7.RELEASE"
|
||||
api "org.synchronoss.cloud:nio-multipart-parser:1.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ You should instead migrate to using `DelegatingPasswordEncoder` to support secur
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
public static NoOpPasswordEncoder passwordEncoder() {
|
||||
public static PasswordEncoder passwordEncoder() {
|
||||
return NoOpPasswordEncoder.getInstance();
|
||||
}
|
||||
----
|
||||
|
||||
@@ -53,7 +53,7 @@ If you wish to override the Spring Security version, you may do so by providing
|
||||
<properties>
|
||||
<!-- ... -->
|
||||
<spring-security.version>{spring-security-version}</spring-security.version>
|
||||
</dependencies>
|
||||
</properties>
|
||||
----
|
||||
====
|
||||
|
||||
@@ -68,7 +68,7 @@ You can do so by adding a Maven property, as the following example shows:
|
||||
<properties>
|
||||
<!-- ... -->
|
||||
<spring.version>{spring-core-version}</spring.version>
|
||||
</dependencies>
|
||||
</properties>
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
@@ -198,10 +198,13 @@ The password package of the spring-security-crypto module provides support for e
|
||||
[source,java]
|
||||
----
|
||||
public interface PasswordEncoder {
|
||||
String encode(CharSequence rawPassword);
|
||||
|
||||
String encode(String rawPassword);
|
||||
boolean matches(CharSequence rawPassword, String encodedPassword);
|
||||
|
||||
boolean matches(String rawPassword, String encodedPassword);
|
||||
default boolean upgradeEncoding(String encodedPassword) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@ It is not only useful but necessary to include the user in the queries to suppor
|
||||
[[data-configuration]]
|
||||
=== Spring Data & Spring Security Configuration
|
||||
|
||||
To use this support, add `org.springframework.security:spring-security-data` dependency and provide a bean of type `SecurityEvaluationContextExtension`.
|
||||
In Java Configuration, this would look like:
|
||||
To use this support, add `org.springframework.security:spring-security-data` dependency and provide a bean of type `SecurityEvaluationContextExtension`:
|
||||
|
||||
[source,java]
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
|
||||
@@ -18,6 +19,16 @@ public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun securityEvaluationContextExtension(): SecurityEvaluationContextExtension {
|
||||
return SecurityEvaluationContextExtension()
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
In XML Configuration, this would look like:
|
||||
|
||||
[source,xml]
|
||||
@@ -31,7 +42,9 @@ In XML Configuration, this would look like:
|
||||
Now Spring Security can be used within your queries.
|
||||
For example:
|
||||
|
||||
[source,java]
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Repository
|
||||
public interface MessageRepository extends PagingAndSortingRepository<Message,Long> {
|
||||
@@ -40,6 +53,17 @@ public interface MessageRepository extends PagingAndSortingRepository<Message,Lo
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Repository
|
||||
interface MessageRepository : PagingAndSortingRepository<Message,Long> {
|
||||
@Query("select m from Message m where m.to.id = ?#{ principal?.id }")
|
||||
fun findInbox(pageable: Pageable): Page<Message>
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
This checks to see if the `Authentication.getPrincipal().getId()` is equal to the recipient of the `Message`.
|
||||
Note that this example assumes you have customized the principal to be an Object that has an id property.
|
||||
By exposing the `SecurityEvaluationContextExtension` bean, all of the <<common-expressions,Common Security Expressions>> are available within the Query.
|
||||
|
||||
@@ -2641,7 +2641,7 @@ Next, we can construct a `JWTProcessor`:
|
||||
JWTProcessor jwtProcessor(JWTClaimSetJWSKeySelector keySelector) {
|
||||
ConfigurableJWTProcessor<SecurityContext> jwtProcessor =
|
||||
new DefaultJWTProcessor();
|
||||
jwtProcessor.setJWTClaimSetJWSKeySelector(keySelector);
|
||||
jwtProcessor.setJWTClaimsSetAwareJWSKeySelector(keySelector);
|
||||
return jwtProcessor;
|
||||
}
|
||||
----
|
||||
@@ -2734,9 +2734,9 @@ Now that we have a tenant-aware processor and a tenant-aware validator, we can p
|
||||
----
|
||||
@Bean
|
||||
JwtDecoder jwtDecoder(JWTProcessor jwtProcessor, OAuth2TokenValidator<Jwt> jwtValidator) {
|
||||
NimbusJwtDecoder decoder = new NimbusJwtDecoder(processor);
|
||||
NimbusJwtDecoder decoder = new NimbusJwtDecoder(jwtProcessor);
|
||||
OAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<>
|
||||
(JwtValidators.createDefault(), this.jwtValidator);
|
||||
(JwtValidators.createDefault(), jwtValidator);
|
||||
decoder.setJwtValidator(validator);
|
||||
return decoder;
|
||||
}
|
||||
|
||||
@@ -739,7 +739,7 @@ But, if you do need something from the request, then you can use create a custom
|
||||
----
|
||||
@Component
|
||||
public class AuthnRequestConverter implements
|
||||
Converter<MySaml2AuthenticationRequestContext, AuthnRequest> {
|
||||
Converter<Saml2AuthenticationRequestContext, AuthnRequest> {
|
||||
|
||||
private final AuthnRequestBuilder authnRequestBuilder;
|
||||
private final IssuerBuilder issuerBuilder;
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
aspectjVersion=1.9.7
|
||||
springJavaformatVersion=0.0.28
|
||||
aspectjVersion=1.9.9.1
|
||||
springJavaformatVersion=0.0.31
|
||||
springBootVersion=2.4.2
|
||||
springFrameworkVersion=5.3.11
|
||||
springFrameworkVersion=5.3.19
|
||||
openSamlVersion=3.4.6
|
||||
version=5.5.3
|
||||
kotlinVersion=1.5.31
|
||||
version=5.5.6
|
||||
kotlinVersion=1.5.32
|
||||
samplesBranch=5.5.x
|
||||
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError
|
||||
org.gradle.parallel=true
|
||||
|
||||
+1
-1
@@ -29,9 +29,9 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Simple expression configuration attribute for use in {@link Message} authorizations.
|
||||
*
|
||||
* @since 4.0
|
||||
* @author Rob Winch
|
||||
* @author Daniel Bustamante Ospina
|
||||
* @since 4.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
class MessageExpressionConfigAttribute implements ConfigAttribute, EvaluationContextPostProcessor<Message<?>> {
|
||||
|
||||
@@ -24,7 +24,7 @@ dependencies {
|
||||
testImplementation 'io.projectreactor:reactor-test'
|
||||
testImplementation 'io.projectreactor.tools:blockhound'
|
||||
testImplementation 'org.skyscreamer:jsonassert'
|
||||
testImplementation 'io.r2dbc:r2dbc-h2:0.8.4.RELEASE'
|
||||
testImplementation 'io.r2dbc:r2dbc-h2:0.8.5.RELEASE'
|
||||
testImplementation 'io.r2dbc:r2dbc-spi-test:0.8.6.RELEASE'
|
||||
|
||||
testRuntimeOnly 'org.hsqldb:hsqldb'
|
||||
|
||||
+1
-1
@@ -58,7 +58,6 @@ import org.springframework.util.CollectionUtils;
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @since 5.0
|
||||
* @deprecated Use {@link DefaultAuthorizationCodeTokenResponseClient}
|
||||
* @see OAuth2AccessTokenResponseClient
|
||||
* @see OAuth2AuthorizationCodeGrantRequest
|
||||
* @see OAuth2AccessTokenResponse
|
||||
@@ -71,6 +70,7 @@ import org.springframework.util.CollectionUtils;
|
||||
* @see <a target="_blank" href=
|
||||
* "https://tools.ietf.org/html/rfc6749#section-4.1.4">Section 4.1.4 Access Token Response
|
||||
* (Authorization Code Grant)</a>
|
||||
* @deprecated Use {@link DefaultAuthorizationCodeTokenResponseClient}
|
||||
*/
|
||||
@Deprecated
|
||||
public class NimbusAuthorizationCodeTokenResponseClient
|
||||
|
||||
+2
-2
@@ -112,8 +112,8 @@ public final class ClientRegistration implements Serializable {
|
||||
|
||||
/**
|
||||
* Returns the uri (or uri template) for the redirection endpoint.
|
||||
* @deprecated Use {@link #getRedirectUri()} instead
|
||||
* @return the uri (or uri template) for the redirection endpoint
|
||||
* @deprecated Use {@link #getRedirectUri()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getRedirectUriTemplate() {
|
||||
@@ -445,10 +445,10 @@ public final class ClientRegistration implements Serializable {
|
||||
|
||||
/**
|
||||
* Sets the uri (or uri template) for the redirection endpoint.
|
||||
* @deprecated Use {@link #redirectUri(String)} instead
|
||||
* @param redirectUriTemplate the uri (or uri template) for the redirection
|
||||
* endpoint
|
||||
* @return the {@link Builder}
|
||||
* @deprecated Use {@link #redirectUri(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder redirectUriTemplate(String redirectUriTemplate) {
|
||||
|
||||
+6
-6
@@ -42,18 +42,18 @@ import org.springframework.web.client.RestTemplate;
|
||||
* {@link OAuth2User} type(s) keyed by {@code String}, which represents the
|
||||
* {@link ClientRegistration#getRegistrationId() Registration Id} of the Client.
|
||||
*
|
||||
* @deprecated It is recommended to use a delegation-based strategy of an
|
||||
* {@link OAuth2UserService} to support custom {@link OAuth2User} types, as it provides
|
||||
* much greater flexibility compared to this implementation. See the
|
||||
* <a target="_blank" href=
|
||||
* "https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2login-advanced-map-authorities-oauth2userservice">reference
|
||||
* manual</a> for details on how to implement.
|
||||
* @author Joe Grandja
|
||||
* @since 5.0
|
||||
* @see OAuth2UserService
|
||||
* @see OAuth2UserRequest
|
||||
* @see OAuth2User
|
||||
* @see ClientRegistration
|
||||
* @deprecated It is recommended to use a delegation-based strategy of an
|
||||
* {@link OAuth2UserService} to support custom {@link OAuth2User} types, as it provides
|
||||
* much greater flexibility compared to this implementation. See the
|
||||
* <a target="_blank" href=
|
||||
* "https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2login-advanced-map-authorities-oauth2userservice">reference
|
||||
* manual</a> for details on how to implement.
|
||||
*/
|
||||
@Deprecated
|
||||
public class CustomUserTypesOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
|
||||
|
||||
+2
-2
@@ -27,13 +27,13 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
* {@link OAuth2UserRequest#getClientRegistration() Client} and returning an
|
||||
* {@link AuthenticatedPrincipal} in the form of an {@link OAuth2User}.
|
||||
*
|
||||
* @param <R> The type of OAuth 2.0 User Request
|
||||
* @param <U> The type of OAuth 2.0 User
|
||||
* @author Joe Grandja
|
||||
* @since 5.0
|
||||
* @see OAuth2UserRequest
|
||||
* @see OAuth2User
|
||||
* @see AuthenticatedPrincipal
|
||||
* @param <R> The type of OAuth 2.0 User Request
|
||||
* @param <U> The type of OAuth 2.0 User
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface OAuth2UserService<R extends OAuth2UserRequest, U extends OAuth2User> {
|
||||
|
||||
+2
-2
@@ -29,13 +29,13 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
* {@link OAuth2UserRequest#getClientRegistration() Client} and returning an
|
||||
* {@link AuthenticatedPrincipal} in the form of an {@link OAuth2User}.
|
||||
*
|
||||
* @param <R> The type of OAuth 2.0 User Request
|
||||
* @param <U> The type of OAuth 2.0 User
|
||||
* @author Rob Winch
|
||||
* @since 5.1
|
||||
* @see OAuth2UserRequest
|
||||
* @see OAuth2User
|
||||
* @see AuthenticatedPrincipal
|
||||
* @param <R> The type of OAuth 2.0 User Request
|
||||
* @param <U> The type of OAuth 2.0 User
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ReactiveOAuth2UserService<R extends OAuth2UserRequest, U extends OAuth2User> {
|
||||
|
||||
+3
-3
@@ -59,12 +59,12 @@ public interface AuthorizationRequestRepository<T extends OAuth2AuthorizationReq
|
||||
/**
|
||||
* Removes and returns the {@link OAuth2AuthorizationRequest} associated to the
|
||||
* provided {@code HttpServletRequest} or if not available returns {@code null}.
|
||||
* @deprecated Use
|
||||
* {@link #removeAuthorizationRequest(HttpServletRequest, HttpServletResponse)}
|
||||
* instead
|
||||
* @param request the {@code HttpServletRequest}
|
||||
* @return the removed {@link OAuth2AuthorizationRequest} or {@code null} if not
|
||||
* available
|
||||
* @deprecated Use
|
||||
* {@link #removeAuthorizationRequest(HttpServletRequest, HttpServletResponse)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
T removeAuthorizationRequest(HttpServletRequest request);
|
||||
|
||||
+3
-3
@@ -156,6 +156,9 @@ public final class OAuth2AuthorizedClientArgumentResolver implements HandlerMeth
|
||||
/**
|
||||
* Sets the client used when requesting an access token credential at the Token
|
||||
* Endpoint for the {@code client_credentials} grant.
|
||||
* @param clientCredentialsTokenResponseClient the client used when requesting an
|
||||
* access token credential at the Token Endpoint for the {@code client_credentials}
|
||||
* grant
|
||||
* @deprecated Use
|
||||
* {@link #OAuth2AuthorizedClientArgumentResolver(OAuth2AuthorizedClientManager)}
|
||||
* instead. Create an instance of
|
||||
@@ -165,9 +168,6 @@ public final class OAuth2AuthorizedClientArgumentResolver implements HandlerMeth
|
||||
* to
|
||||
* {@link DefaultOAuth2AuthorizedClientManager#setAuthorizedClientProvider(OAuth2AuthorizedClientProvider)
|
||||
* DefaultOAuth2AuthorizedClientManager}.
|
||||
* @param clientCredentialsTokenResponseClient the client used when requesting an
|
||||
* access token credential at the Token Endpoint for the {@code client_credentials}
|
||||
* grant
|
||||
*/
|
||||
@Deprecated
|
||||
public void setClientCredentialsTokenResponseClient(
|
||||
|
||||
+2
-2
@@ -355,6 +355,7 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
||||
/**
|
||||
* Sets the {@link ReactiveOAuth2AccessTokenResponseClient} used for getting an
|
||||
* {@link OAuth2AuthorizedClient} for the client_credentials grant.
|
||||
* @param clientCredentialsTokenResponseClient the client to use
|
||||
* @deprecated Use
|
||||
* {@link #ServerOAuth2AuthorizedClientExchangeFilterFunction(ReactiveOAuth2AuthorizedClientManager)}
|
||||
* instead. Create an instance of
|
||||
@@ -364,7 +365,6 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
||||
* supply it to
|
||||
* {@link DefaultReactiveOAuth2AuthorizedClientManager#setAuthorizedClientProvider(ReactiveOAuth2AuthorizedClientProvider)
|
||||
* DefaultReactiveOAuth2AuthorizedClientManager}.
|
||||
* @param clientCredentialsTokenResponseClient the client to use
|
||||
*/
|
||||
@Deprecated
|
||||
public void setClientCredentialsTokenResponseClient(
|
||||
@@ -407,13 +407,13 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
|
||||
/**
|
||||
* An access token will be considered expired by comparing its expiration to now +
|
||||
* this skewed Duration. The default is 1 minute.
|
||||
* @param accessTokenExpiresSkew the Duration to use.
|
||||
* @deprecated The {@code accessTokenExpiresSkew} should be configured with the
|
||||
* specific {@link ReactiveOAuth2AuthorizedClientProvider} implementation, e.g.
|
||||
* {@link ClientCredentialsReactiveOAuth2AuthorizedClientProvider#setClockSkew(Duration)
|
||||
* ClientCredentialsReactiveOAuth2AuthorizedClientProvider} or
|
||||
* {@link RefreshTokenReactiveOAuth2AuthorizedClientProvider#setClockSkew(Duration)
|
||||
* RefreshTokenReactiveOAuth2AuthorizedClientProvider}.
|
||||
* @param accessTokenExpiresSkew the Duration to use.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAccessTokenExpiresSkew(Duration accessTokenExpiresSkew) {
|
||||
|
||||
+2
-2
@@ -239,6 +239,7 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
||||
/**
|
||||
* Sets the {@link OAuth2AccessTokenResponseClient} used for getting an
|
||||
* {@link OAuth2AuthorizedClient} for the client_credentials grant.
|
||||
* @param clientCredentialsTokenResponseClient the client to use
|
||||
* @deprecated Use
|
||||
* {@link #ServletOAuth2AuthorizedClientExchangeFilterFunction(OAuth2AuthorizedClientManager)}
|
||||
* instead. Create an instance of
|
||||
@@ -248,7 +249,6 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
||||
* to
|
||||
* {@link DefaultOAuth2AuthorizedClientManager#setAuthorizedClientProvider(OAuth2AuthorizedClientProvider)
|
||||
* DefaultOAuth2AuthorizedClientManager}.
|
||||
* @param clientCredentialsTokenResponseClient the client to use
|
||||
*/
|
||||
@Deprecated
|
||||
public void setClientCredentialsTokenResponseClient(
|
||||
@@ -397,13 +397,13 @@ public final class ServletOAuth2AuthorizedClientExchangeFilterFunction implement
|
||||
/**
|
||||
* An access token will be considered expired by comparing its expiration to now +
|
||||
* this skewed Duration. The default is 1 minute.
|
||||
* @param accessTokenExpiresSkew the Duration to use.
|
||||
* @deprecated The {@code accessTokenExpiresSkew} should be configured with the
|
||||
* specific {@link OAuth2AuthorizedClientProvider} implementation, e.g.
|
||||
* {@link ClientCredentialsOAuth2AuthorizedClientProvider#setClockSkew(Duration)
|
||||
* ClientCredentialsOAuth2AuthorizedClientProvider} or
|
||||
* {@link RefreshTokenOAuth2AuthorizedClientProvider#setClockSkew(Duration)
|
||||
* RefreshTokenOAuth2AuthorizedClientProvider}.
|
||||
* @param accessTokenExpiresSkew the Duration to use.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAccessTokenExpiresSkew(Duration accessTokenExpiresSkew) {
|
||||
|
||||
+2
-2
@@ -35,10 +35,10 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
* {@link ServerWebExchange} is null and that the {@link Authentication} is either null or
|
||||
* anonymous to prevent using it incorrectly.
|
||||
*
|
||||
* @deprecated Use {@link AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager}
|
||||
* instead
|
||||
* @author Rob Winch
|
||||
* @since 5.1
|
||||
* @deprecated Use {@link AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class UnAuthenticatedServerOAuth2AuthorizedClientRepository implements ServerOAuth2AuthorizedClientRepository {
|
||||
|
||||
+1
-2
@@ -42,11 +42,10 @@ public interface ClaimAccessor {
|
||||
/**
|
||||
* Returns the claim value as a {@code T} type. The claim value is expected to be of
|
||||
* type {@code T}.
|
||||
*
|
||||
* @since 5.2
|
||||
* @param claim the name of the claim
|
||||
* @param <T> the type of the claim value
|
||||
* @return the claim value
|
||||
* @since 5.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default <T> T getClaim(String claim) {
|
||||
|
||||
+1
@@ -34,6 +34,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Joe Grandja
|
||||
* @author Nikita Konev
|
||||
* @since 5.3
|
||||
* @deprecated Use {@link DefaultMapOAuth2AccessTokenResponseConverter} instead
|
||||
*/
|
||||
public final class MapOAuth2AccessTokenResponseConverter
|
||||
implements Converter<Map<String, String>, OAuth2AccessTokenResponse> {
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Joe Grandja
|
||||
* @author Nikita Konev
|
||||
* @since 5.3
|
||||
* @deprecated Use {@link DefaultOAuth2AccessTokenResponseMapConverter} instead
|
||||
*/
|
||||
public final class OAuth2AccessTokenResponseMapConverter
|
||||
implements Converter<OAuth2AccessTokenResponse, Map<String, String>> {
|
||||
|
||||
+3
@@ -110,6 +110,7 @@ public class OAuth2AccessTokenResponseHttpMessageConverter
|
||||
* parameters to an {@link OAuth2AccessTokenResponse}.
|
||||
* @param tokenResponseConverter the {@link Converter} used for converting to an
|
||||
* {@link OAuth2AccessTokenResponse}
|
||||
* @deprecated Use {@link #setAccessTokenResponseConverter(Converter)} instead
|
||||
*/
|
||||
public final void setTokenResponseConverter(
|
||||
Converter<Map<String, String>, OAuth2AccessTokenResponse> tokenResponseConverter) {
|
||||
@@ -123,6 +124,8 @@ public class OAuth2AccessTokenResponseHttpMessageConverter
|
||||
* Access Token Response parameters.
|
||||
* @param tokenResponseParametersConverter the {@link Converter} used for converting
|
||||
* to a {@code Map} representation of the Access Token Response parameters
|
||||
* @deprecated Use {@link #setAccessTokenResponseParametersConverter(Converter)}
|
||||
* instead
|
||||
*/
|
||||
public final void setTokenResponseParametersConverter(
|
||||
Converter<OAuth2AccessTokenResponse, Map<String, String>> tokenResponseParametersConverter) {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -54,7 +54,7 @@ public final class JwtClaimValidator<T> implements OAuth2TokenValidator<Jwt> {
|
||||
Assert.notNull(test, "test can not be null");
|
||||
this.claim = claim;
|
||||
this.test = test;
|
||||
this.error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST, "The " + this.claim + " claim is not valid",
|
||||
this.error = new OAuth2Error(OAuth2ErrorCodes.INVALID_TOKEN, "The " + this.claim + " claim is not valid",
|
||||
"https://tools.ietf.org/html/rfc6750#section-3.1");
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -20,11 +20,11 @@ package org.springframework.security.oauth2.jwt;
|
||||
* A factory for {@link JwtDecoder}(s). This factory should be supplied with a type that
|
||||
* provides contextual information used to create a specific {@code JwtDecoder}.
|
||||
*
|
||||
* @param <C> The type that provides contextual information used to create a specific
|
||||
* {@code JwtDecoder}.
|
||||
* @author Joe Grandja
|
||||
* @since 5.2
|
||||
* @see JwtDecoder
|
||||
* @param <C> The type that provides contextual information used to create a specific
|
||||
* {@code JwtDecoder}.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface JwtDecoderFactory<C> {
|
||||
|
||||
+1
-1
@@ -35,7 +35,6 @@ import org.springframework.web.client.RestOperations;
|
||||
* <p>
|
||||
* <b>NOTE:</b> This implementation uses the Nimbus JOSE + JWT SDK internally.
|
||||
*
|
||||
* @deprecated Use {@link NimbusJwtDecoder} or {@link JwtDecoders} instead
|
||||
* @author Joe Grandja
|
||||
* @author Josh Cummings
|
||||
* @since 5.0
|
||||
@@ -49,6 +48,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* (JWK)</a>
|
||||
* @see <a target="_blank" href="https://connect2id.com/products/nimbus-jose-jwt">Nimbus
|
||||
* JOSE + JWT SDK</a>
|
||||
* @deprecated Use {@link NimbusJwtDecoder} or {@link JwtDecoders} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public final class NimbusJwtDecoderJwkSupport implements JwtDecoder {
|
||||
|
||||
+2
-2
@@ -21,11 +21,11 @@ package org.springframework.security.oauth2.jwt;
|
||||
* type that provides contextual information used to create a specific
|
||||
* {@code ReactiveJwtDecoder}.
|
||||
*
|
||||
* @param <C> The type that provides contextual information used to create a specific
|
||||
* {@code ReactiveJwtDecoder}.
|
||||
* @author Joe Grandja
|
||||
* @since 5.2
|
||||
* @see ReactiveJwtDecoder
|
||||
* @param <C> The type that provides contextual information used to create a specific
|
||||
* {@code ReactiveJwtDecoder}.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ReactiveJwtDecoderFactory<C> {
|
||||
|
||||
+7
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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,10 +16,14 @@
|
||||
|
||||
package org.springframework.security.oauth2.jwt;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -45,7 +49,9 @@ public class JwtClaimValidatorTests {
|
||||
@Test
|
||||
public void validateWhenClaimFailsTheTestThenReturnsFailure() {
|
||||
Jwt jwt = TestJwts.jwt().claim(JwtClaimNames.ISS, "http://abc").build();
|
||||
Collection<OAuth2Error> details = this.validator.validate(jwt).getErrors();
|
||||
assertThat(this.validator.validate(jwt).getErrors().isEmpty()).isFalse();
|
||||
assertThat(details).allMatch((error) -> Objects.equals(error.getErrorCode(), OAuth2ErrorCodes.INVALID_TOKEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+4
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 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.time.ZoneId;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -64,6 +65,7 @@ public class JwtTimestampValidatorTests {
|
||||
.collect(Collectors.toList());
|
||||
// @formatter:on
|
||||
assertThat(messages).contains("Jwt expired at " + oneHourAgo);
|
||||
assertThat(details).allMatch((error) -> Objects.equals(error.getErrorCode(), OAuth2ErrorCodes.INVALID_TOKEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -78,6 +80,7 @@ public class JwtTimestampValidatorTests {
|
||||
.collect(Collectors.toList());
|
||||
// @formatter:on
|
||||
assertThat(messages).contains("Jwt used before " + oneHourFromNow);
|
||||
assertThat(details).allMatch((error) -> Objects.equals(error.getErrorCode(), OAuth2ErrorCodes.INVALID_TOKEN));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.security.oauth2.server.resource.authentication;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -186,7 +187,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver
|
||||
return this.authenticationManagers.computeIfAbsent(issuer,
|
||||
(k) -> Mono.<ReactiveAuthenticationManager>fromCallable(() -> new JwtReactiveAuthenticationManager(ReactiveJwtDecoders.fromIssuerLocation(k)))
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.cache()
|
||||
.cache((manager) -> Duration.ofMillis(Long.MAX_VALUE), (ex) -> Duration.ZERO, () -> Duration.ZERO)
|
||||
);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ import org.springframework.security.oauth2.core.ClaimAccessor;
|
||||
* @see OAuth2IntrospectionAuthenticatedPrincipal
|
||||
* @see <a target="_blank" href=
|
||||
* "https://tools.ietf.org/html/rfc7662#section-2.2">Introspection Response</a>
|
||||
* @deprecated Use {@link OAuth2TokenIntrospectionClaimAccessor} instead
|
||||
*/
|
||||
public interface OAuth2IntrospectionClaimAccessor extends ClaimAccessor {
|
||||
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ package org.springframework.security.oauth2.server.resource.introspection;
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 5.2
|
||||
* @deprecated Use {@link OAuth2TokenIntrospectionClaimNames} instead
|
||||
*/
|
||||
public interface OAuth2IntrospectionClaimNames {
|
||||
|
||||
|
||||
+38
@@ -96,6 +96,44 @@ public class JwtIssuerAuthenticationManagerResolverTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhednUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception {
|
||||
try (MockWebServer server = new MockWebServer()) {
|
||||
server.start();
|
||||
String issuer = server.url("").toString();
|
||||
// @formatter:off
|
||||
server.enqueue(new MockResponse().setResponseCode(500)
|
||||
.setHeader("Content-Type", "application/json")
|
||||
.setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer))
|
||||
);
|
||||
server.enqueue(new MockResponse().setResponseCode(200)
|
||||
.setHeader("Content-Type", "application/json")
|
||||
.setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer))
|
||||
);
|
||||
server.enqueue(new MockResponse().setResponseCode(200)
|
||||
.setHeader("Content-Type", "application/json")
|
||||
.setBody(JWK_SET)
|
||||
);
|
||||
server.enqueue(new MockResponse().setResponseCode(200)
|
||||
.setHeader("Content-Type", "application/json")
|
||||
.setBody(JWK_SET)
|
||||
);
|
||||
// @formatter:on
|
||||
JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256),
|
||||
new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer))));
|
||||
jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY));
|
||||
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver(
|
||||
issuer);
|
||||
Authentication token = withBearerToken(jws.serialize());
|
||||
AuthenticationManager authenticationManager = authenticationManagerResolver.resolve(null);
|
||||
assertThat(authenticationManager).isNotNull();
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> authenticationManager.authenticate(token));
|
||||
Authentication authentication = authenticationManager.authenticate(token);
|
||||
assertThat(authentication.isAuthenticated()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenUsingSameIssuerThenReturnsSameAuthenticationManager() throws Exception {
|
||||
try (MockWebServer server = new MockWebServer()) {
|
||||
|
||||
+30
@@ -95,6 +95,36 @@ public class JwtIssuerReactiveAuthenticationManagerResolverTests {
|
||||
}
|
||||
}
|
||||
|
||||
// gh-10444
|
||||
@Test
|
||||
public void resolveWhednUsingTrustedIssuerThenReturnsAuthenticationManager() throws Exception {
|
||||
try (MockWebServer server = new MockWebServer()) {
|
||||
String issuer = server.url("").toString();
|
||||
// @formatter:off
|
||||
server.enqueue(new MockResponse().setResponseCode(500).setHeader("Content-Type", "application/json")
|
||||
.setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer)));
|
||||
server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json")
|
||||
.setBody(String.format(DEFAULT_RESPONSE_TEMPLATE, issuer, issuer)));
|
||||
server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json")
|
||||
.setBody(JWK_SET));
|
||||
server.enqueue(new MockResponse().setResponseCode(200).setHeader("Content-Type", "application/json")
|
||||
.setBody(JWK_SET));
|
||||
// @formatter:on
|
||||
JWSObject jws = new JWSObject(new JWSHeader(JWSAlgorithm.RS256),
|
||||
new Payload(new JSONObject(Collections.singletonMap(JwtClaimNames.ISS, issuer))));
|
||||
jws.sign(new RSASSASigner(TestKeys.DEFAULT_PRIVATE_KEY));
|
||||
JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver(
|
||||
issuer);
|
||||
ReactiveAuthenticationManager authenticationManager = authenticationManagerResolver.resolve(null).block();
|
||||
assertThat(authenticationManager).isNotNull();
|
||||
Authentication token = withBearerToken(jws.serialize());
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> authenticationManager.authenticate(token).block());
|
||||
Authentication authentication = authenticationManager.authenticate(token).block();
|
||||
assertThat(authentication.isAuthenticated()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenUsingSameIssuerThenReturnsSameAuthenticationManager() throws Exception {
|
||||
try (MockWebServer server = new MockWebServer()) {
|
||||
|
||||
@@ -43,12 +43,12 @@ import org.openid4java.message.ax.FetchResponse;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Ray Krueger
|
||||
* @author Luke Taylor
|
||||
* @deprecated The OpenID 1.0 and 2.0 protocols have been deprecated and users are
|
||||
* <a href="https://openid.net/specs/openid-connect-migration-1_0.html">encouraged to
|
||||
* migrate</a> to <a href="https://openid.net/connect/">OpenID Connect</a>, which is
|
||||
* supported by <code>spring-security-oauth2</code>.
|
||||
* @author Ray Krueger
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
+4
-4
@@ -126,6 +126,10 @@ final class OpenSamlSigningUtils {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
private OpenSamlSigningUtils() {
|
||||
|
||||
}
|
||||
|
||||
static class QueryParametersPartial {
|
||||
|
||||
final RelyingPartyRegistration registration;
|
||||
@@ -166,8 +170,4 @@ final class OpenSamlSigningUtils {
|
||||
|
||||
}
|
||||
|
||||
private OpenSamlSigningUtils() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -85,6 +85,10 @@ final class OpenSamlVerificationUtils {
|
||||
DefaultSecurityConfigurationBootstrap.buildBasicInlineKeyInfoCredentialResolver());
|
||||
}
|
||||
|
||||
private OpenSamlVerificationUtils() {
|
||||
|
||||
}
|
||||
|
||||
static class VerifierPartial {
|
||||
|
||||
private final String id;
|
||||
@@ -210,8 +214,4 @@ final class OpenSamlVerificationUtils {
|
||||
|
||||
}
|
||||
|
||||
private OpenSamlVerificationUtils() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-6
@@ -19,13 +19,12 @@ package org.springframework.security.saml2.provider.service.authentication;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterOutputStream;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import org.springframework.security.saml2.Saml2Exception;
|
||||
|
||||
/**
|
||||
@@ -33,17 +32,15 @@ import org.springframework.security.saml2.Saml2Exception;
|
||||
*/
|
||||
final class Saml2Utils {
|
||||
|
||||
private static Base64 BASE64 = new Base64(0, new byte[] { '\n' });
|
||||
|
||||
private Saml2Utils() {
|
||||
}
|
||||
|
||||
static String samlEncode(byte[] b) {
|
||||
return BASE64.encodeAsString(b);
|
||||
return Base64.getMimeEncoder().encodeToString(b);
|
||||
}
|
||||
|
||||
static byte[] samlDecode(String s) {
|
||||
return BASE64.decode(s);
|
||||
return Base64.getMimeDecoder().decode(s);
|
||||
}
|
||||
|
||||
static byte[] samlDeflate(String s) {
|
||||
|
||||
+8
-8
@@ -21,7 +21,7 @@ import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -383,7 +383,7 @@ public final class RelyingPartyRegistration {
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
PrivateKey privateKey = credential.getPrivateKey();
|
||||
X509Certificate certificate = credential.getCertificate();
|
||||
Set<Saml2X509Credential.Saml2X509CredentialType> credentialTypes = new HashSet<>();
|
||||
Set<Saml2X509Credential.Saml2X509CredentialType> credentialTypes = new LinkedHashSet<>();
|
||||
if (credential.isSigningCredential()) {
|
||||
credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.SIGNING);
|
||||
}
|
||||
@@ -403,7 +403,7 @@ public final class RelyingPartyRegistration {
|
||||
Saml2X509Credential credential) {
|
||||
PrivateKey privateKey = credential.getPrivateKey();
|
||||
X509Certificate certificate = credential.getCertificate();
|
||||
Set<org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType> credentialTypes = new HashSet<>();
|
||||
Set<org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType> credentialTypes = new LinkedHashSet<>();
|
||||
if (credential.isSigningCredential()) {
|
||||
credentialTypes.add(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.SIGNING);
|
||||
@@ -573,9 +573,9 @@ public final class RelyingPartyRegistration {
|
||||
|
||||
private List<String> signingAlgorithms = new ArrayList<>();
|
||||
|
||||
private Collection<Saml2X509Credential> verificationX509Credentials = new HashSet<>();
|
||||
private Collection<Saml2X509Credential> verificationX509Credentials = new LinkedHashSet<>();
|
||||
|
||||
private Collection<Saml2X509Credential> encryptionX509Credentials = new HashSet<>();
|
||||
private Collection<Saml2X509Credential> encryptionX509Credentials = new LinkedHashSet<>();
|
||||
|
||||
private String singleSignOnServiceLocation;
|
||||
|
||||
@@ -822,9 +822,9 @@ public final class RelyingPartyRegistration {
|
||||
|
||||
private String entityId = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
|
||||
|
||||
private Collection<Saml2X509Credential> signingX509Credentials = new HashSet<>();
|
||||
private Collection<Saml2X509Credential> signingX509Credentials = new LinkedHashSet<>();
|
||||
|
||||
private Collection<Saml2X509Credential> decryptionX509Credentials = new HashSet<>();
|
||||
private Collection<Saml2X509Credential> decryptionX509Credentials = new LinkedHashSet<>();
|
||||
|
||||
private String assertionConsumerServiceLocation = "{baseUrl}/login/saml2/sso/{registrationId}";
|
||||
|
||||
@@ -832,7 +832,7 @@ public final class RelyingPartyRegistration {
|
||||
|
||||
private ProviderDetails.Builder providerDetails = new ProviderDetails.Builder();
|
||||
|
||||
private Collection<org.springframework.security.saml2.credentials.Saml2X509Credential> credentials = new HashSet<>();
|
||||
private Collection<org.springframework.security.saml2.credentials.Saml2X509Credential> credentials = new LinkedHashSet<>();
|
||||
|
||||
private Builder(String registrationId) {
|
||||
this.registrationId = registrationId;
|
||||
|
||||
+8
-6
@@ -19,28 +19,30 @@ package org.springframework.security.saml2.core;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterOutputStream;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import org.springframework.security.saml2.Saml2Exception;
|
||||
|
||||
public final class Saml2Utils {
|
||||
|
||||
private static Base64 BASE64 = new Base64(0, new byte[] { '\n' });
|
||||
|
||||
private Saml2Utils() {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static String samlEncodeNotRfc2045(byte[] b) {
|
||||
return Base64.getEncoder().encodeToString(b);
|
||||
}
|
||||
|
||||
public static String samlEncode(byte[] b) {
|
||||
return BASE64.encodeAsString(b);
|
||||
return Base64.getMimeEncoder().encodeToString(b);
|
||||
}
|
||||
|
||||
public static byte[] samlDecode(String s) {
|
||||
return BASE64.decode(s);
|
||||
return Base64.getMimeDecoder().decode(s);
|
||||
}
|
||||
|
||||
public static byte[] samlDeflate(String s) {
|
||||
|
||||
+51
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -51,6 +51,10 @@ public final class TestSaml2X509Credentials {
|
||||
return new Saml2X509Credential(idpCertificate(), Saml2X509CredentialType.VERIFICATION);
|
||||
}
|
||||
|
||||
public static Saml2X509Credential relyingPartyEncryptingCredential() {
|
||||
return new Saml2X509Credential(idpCertificate(), Saml2X509CredentialType.ENCRYPTION);
|
||||
}
|
||||
|
||||
public static Saml2X509Credential relyingPartySigningCredential() {
|
||||
return new Saml2X509Credential(spPrivateKey(), spCertificate(), Saml2X509CredentialType.SIGNING);
|
||||
}
|
||||
@@ -59,6 +63,16 @@ public final class TestSaml2X509Credentials {
|
||||
return new Saml2X509Credential(spPrivateKey(), spCertificate(), Saml2X509CredentialType.DECRYPTION);
|
||||
}
|
||||
|
||||
public static Saml2X509Credential altPublicCredential() {
|
||||
return new Saml2X509Credential(altCertificate(), Saml2X509CredentialType.VERIFICATION,
|
||||
Saml2X509CredentialType.ENCRYPTION);
|
||||
}
|
||||
|
||||
public static Saml2X509Credential altPrivateCredential() {
|
||||
return new Saml2X509Credential(altPrivateKey(), altCertificate(), Saml2X509CredentialType.SIGNING,
|
||||
Saml2X509CredentialType.DECRYPTION);
|
||||
}
|
||||
|
||||
private static X509Certificate certificate(String cert) {
|
||||
ByteArrayInputStream certBytes = new ByteArrayInputStream(cert.getBytes());
|
||||
try {
|
||||
@@ -170,4 +184,40 @@ public final class TestSaml2X509Credentials {
|
||||
+ "-----END PRIVATE KEY-----");
|
||||
}
|
||||
|
||||
private static X509Certificate altCertificate() {
|
||||
return certificate(
|
||||
"-----BEGIN CERTIFICATE-----\n" + "MIICkDCCAfkCFEstVfmWSFQp/j88GaMUwqVK72adMA0GCSqGSIb3DQEBCwUAMIGG\n"
|
||||
+ "MQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjESMBAGA1UEBwwJVmFu\n"
|
||||
+ "Y291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FNTDEMMAoGA1UECwwD\n"
|
||||
+ "YWx0MSEwHwYDVQQDDBhhbHQuc3ByaW5nLnNlY3VyaXR5LnNhbWwwHhcNMjIwMjEw\n"
|
||||
+ "MTY1ODA4WhcNMzIwMjEwMTY1ODA4WjCBhjELMAkGA1UEBhMCVVMxEzARBgNVBAgM\n"
|
||||
+ "Cldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsGA1UECgwUU3ByaW5n\n"
|
||||
+ "IFNlY3VyaXR5IFNBTUwxDDAKBgNVBAsMA2FsdDEhMB8GA1UEAwwYYWx0LnNwcmlu\n"
|
||||
+ "Zy5zZWN1cml0eS5zYW1sMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9ZGWj\n"
|
||||
+ "TPDsymQCJL044py4xLsBI/S9RvzNeR9oD/tHyoxCE+YZzjf0PyBtwqKzkKWqCPf4\n"
|
||||
+ "XGUYHfEpkM5kJYwCW8TsOx5fnwLIQweiPqjYrBr/O0IjHMqYG9HlR/ros7iBt4ab\n"
|
||||
+ "EGUu/B9yYg1YRYPxKQ6TNP3AD+9tBT8TsFFyjwIDAQABMA0GCSqGSIb3DQEBCwUA\n"
|
||||
+ "A4GBAKJf2VHLjkCHRxlbWn63jGiquq3ENYgd1JS0DZ3ggFmuc6zQiqxzRGtArIDZ\n"
|
||||
+ "0jH5nrG0jcvO0fqDqBQh0iT8thfUnkViAQvACZ9a+0x0NzUicJ+Ra51c8Z2enqbg\n"
|
||||
+ "pXy+ga67HcAXrDekm1MCGCgiEb/Cgl41lsideqhC8Efl7PRN\n" + "-----END CERTIFICATE-----");
|
||||
}
|
||||
|
||||
private static PrivateKey altPrivateKey() {
|
||||
return privateKey(
|
||||
"-----BEGIN PRIVATE KEY-----\n" + "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAL1kZaNM8OzKZAIk\n"
|
||||
+ "vTjinLjEuwEj9L1G/M15H2gP+0fKjEIT5hnON/Q/IG3CorOQpaoI9/hcZRgd8SmQ\n"
|
||||
+ "zmQljAJbxOw7Hl+fAshDB6I+qNisGv87QiMcypgb0eVH+uizuIG3hpsQZS78H3Ji\n"
|
||||
+ "DVhFg/EpDpM0/cAP720FPxOwUXKPAgMBAAECgYEApYKslAZ0cer5dSoYNzNLFOnQ\n"
|
||||
+ "J1H92r/Dw+k6+h0lUvr+keyD5T9jhM76DxHOUDBzpmIKGoDcVDQugk2rILfzXsQA\n"
|
||||
+ "JtwvDRJk32Z02Vt0jb7t/WUOOQhjKCjQuv9/tOx90GCl0VxYG69UOjaMRWrlg/i9\n"
|
||||
+ "6/zcTRIahIn5XxF0psECQQD7ivJCpDbOLJGsc8gNJR4cvjZ1q0mHIOrbKqJC0y1n\n"
|
||||
+ "5DrzGEflPeyCUwnOKNp9HJQP8gmZzXfj0JM9KsjpiUChAkEAwL+FmhDoTiqStIrH\n"
|
||||
+ "h9Kdnsev//imMmRHxjwDhntYvqavUsISRmY3imd8inoYq5dzWQMzBtoTyMRmqeLT\n"
|
||||
+ "DHV1LwJAW4xaV37Eo4z9B7Kr4Hzd1MA1ueW5QQDt+Q4vN/r7z4/1FHyFzh0Xcucd\n"
|
||||
+ "7nZX7qj0CkmgzOVG+Rb0P5LOxJA7gQJBAK1KQ2qNct375qPM9bEGSVGchH6k5X7+\n"
|
||||
+ "q4ztHdpFgTb/EzdbZiTG935GpjC1rwJuinTnrHOnkwv4j7iDRm24GF8CQQDqPvrQ\n"
|
||||
+ "GcItR6UUy0q/B8UxLzlE6t+HiznfiJKfyGgCHU56Y4/ZhzSQz2MZHz9SK4DsUL9s\n" + "bOYrWq8VY2fyjV1t\n"
|
||||
+ "-----END PRIVATE KEY-----");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+64
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2022 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,7 +18,8 @@ package org.springframework.security.saml2.provider.service.registration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
|
||||
import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||
import org.springframework.security.saml2.core.TestSaml2X509Credentials;
|
||||
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -81,9 +82,68 @@ public class RelyingPartyRegistrationTests {
|
||||
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId("id")
|
||||
.entityId("entity-id").assertionConsumerServiceLocation("location")
|
||||
.assertingPartyDetails((assertingParty) -> assertingParty.entityId("entity-id")
|
||||
.singleSignOnServiceLocation("location"))
|
||||
.credentials((c) -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential())).build();
|
||||
.singleSignOnServiceLocation("location").verificationX509Credentials(
|
||||
(c) -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential())))
|
||||
.build();
|
||||
assertThat(relyingPartyRegistration.getAssertionConsumerServiceBinding()).isEqualTo(Saml2MessageBinding.POST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildPreservesCredentialsOrder() {
|
||||
Saml2X509Credential altRpCredential = TestSaml2X509Credentials.altPrivateCredential();
|
||||
Saml2X509Credential altApCredential = TestSaml2X509Credentials.altPublicCredential();
|
||||
Saml2X509Credential verifyingCredential = TestSaml2X509Credentials.relyingPartyVerifyingCredential();
|
||||
Saml2X509Credential encryptingCredential = TestSaml2X509Credentials.relyingPartyEncryptingCredential();
|
||||
Saml2X509Credential signingCredential = TestSaml2X509Credentials.relyingPartySigningCredential();
|
||||
Saml2X509Credential decryptionCredential = TestSaml2X509Credentials.relyingPartyDecryptingCredential();
|
||||
|
||||
// Test with the alt credentials first
|
||||
RelyingPartyRegistration relyingPartyRegistration = TestRelyingPartyRegistrations.noCredentials()
|
||||
.assertingPartyDetails((assertingParty) -> assertingParty.verificationX509Credentials((c) -> {
|
||||
c.add(altApCredential);
|
||||
c.add(verifyingCredential);
|
||||
}).encryptionX509Credentials((c) -> {
|
||||
c.add(altApCredential);
|
||||
c.add(encryptingCredential);
|
||||
})).signingX509Credentials((c) -> {
|
||||
c.add(altRpCredential);
|
||||
c.add(signingCredential);
|
||||
}).decryptionX509Credentials((c) -> {
|
||||
c.add(altRpCredential);
|
||||
c.add(decryptionCredential);
|
||||
}).build();
|
||||
assertThat(relyingPartyRegistration.getSigningX509Credentials()).containsExactly(altRpCredential,
|
||||
signingCredential);
|
||||
assertThat(relyingPartyRegistration.getDecryptionX509Credentials()).containsExactly(altRpCredential,
|
||||
decryptionCredential);
|
||||
assertThat(relyingPartyRegistration.getAssertingPartyDetails().getVerificationX509Credentials())
|
||||
.containsExactly(altApCredential, verifyingCredential);
|
||||
assertThat(relyingPartyRegistration.getAssertingPartyDetails().getEncryptionX509Credentials())
|
||||
.containsExactly(altApCredential, encryptingCredential);
|
||||
|
||||
// Test with the alt credentials last
|
||||
relyingPartyRegistration = TestRelyingPartyRegistrations.noCredentials()
|
||||
.assertingPartyDetails((assertingParty) -> assertingParty.verificationX509Credentials((c) -> {
|
||||
c.add(verifyingCredential);
|
||||
c.add(altApCredential);
|
||||
}).encryptionX509Credentials((c) -> {
|
||||
c.add(encryptingCredential);
|
||||
c.add(altApCredential);
|
||||
})).signingX509Credentials((c) -> {
|
||||
c.add(signingCredential);
|
||||
c.add(altRpCredential);
|
||||
}).decryptionX509Credentials((c) -> {
|
||||
c.add(decryptionCredential);
|
||||
c.add(altRpCredential);
|
||||
}).build();
|
||||
assertThat(relyingPartyRegistration.getSigningX509Credentials()).containsExactly(signingCredential,
|
||||
altRpCredential);
|
||||
assertThat(relyingPartyRegistration.getDecryptionX509Credentials()).containsExactly(decryptionCredential,
|
||||
altRpCredential);
|
||||
assertThat(relyingPartyRegistration.getAssertingPartyDetails().getVerificationX509Credentials())
|
||||
.containsExactly(verifyingCredential, altApCredential);
|
||||
assertThat(relyingPartyRegistration.getAssertingPartyDetails().getEncryptionX509Credentials())
|
||||
.containsExactly(encryptingCredential, altApCredential);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -60,7 +60,8 @@ public class Saml2AuthenticationTokenConverterTests {
|
||||
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class)))
|
||||
.willReturn(this.relyingPartyRegistration);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setParameter("SAMLResponse", Saml2Utils.samlEncode("response".getBytes(StandardCharsets.UTF_8)));
|
||||
request.setParameter("SAMLResponse",
|
||||
Saml2Utils.samlEncodeNotRfc2045("response".getBytes(StandardCharsets.UTF_8)));
|
||||
Saml2AuthenticationToken token = converter.convert(request);
|
||||
assertThat(token.getSaml2Response()).isEqualTo("response");
|
||||
assertThat(token.getRelyingPartyRegistration().getRegistrationId())
|
||||
@@ -111,7 +112,7 @@ public class Saml2AuthenticationTokenConverterTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("GET");
|
||||
byte[] deflated = Saml2Utils.samlDeflate("response");
|
||||
String encoded = Saml2Utils.samlEncode(deflated);
|
||||
String encoded = Saml2Utils.samlEncodeNotRfc2045(deflated);
|
||||
request.setParameter("SAMLResponse", encoded);
|
||||
Saml2AuthenticationToken token = converter.convert(request);
|
||||
assertThat(token.getSaml2Response()).isEqualTo("response");
|
||||
|
||||
+2
-3
@@ -41,8 +41,6 @@ import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.util.StringUtils;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -102,6 +100,7 @@ import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
@@ -1206,7 +1205,7 @@ public final class SecurityMockMvcRequestPostProcessors {
|
||||
return getAuthorities((Collection) scope);
|
||||
}
|
||||
String scopes = scope.toString();
|
||||
if (StringUtils.isBlank(scopes)) {
|
||||
if (!StringUtils.hasText(scopes)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return getAuthorities(Arrays.asList(scopes.split(" ")));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -48,7 +48,12 @@ public final class DefaultSecurityFilterChain implements SecurityFilterChain {
|
||||
}
|
||||
|
||||
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
|
||||
logger.info(LogMessage.format("Will secure %s with %s", requestMatcher, filters));
|
||||
if (!filters.isEmpty()) {
|
||||
logger.info(LogMessage.format("Will not secure %s", requestMatcher));
|
||||
}
|
||||
else {
|
||||
logger.info(LogMessage.format("Will secure %s with %s", requestMatcher, filters));
|
||||
}
|
||||
this.requestMatcher = requestMatcher;
|
||||
this.filters = new ArrayList<>(filters);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
* Copyright 2002-2021 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,6 +29,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -78,10 +79,19 @@ public class FilterInvocation {
|
||||
}
|
||||
|
||||
public FilterInvocation(String contextPath, String servletPath, String method) {
|
||||
this(contextPath, servletPath, null, null, method);
|
||||
this(contextPath, servletPath, method, null);
|
||||
}
|
||||
|
||||
public FilterInvocation(String contextPath, String servletPath, String method, ServletContext servletContext) {
|
||||
this(contextPath, servletPath, null, null, method, servletContext);
|
||||
}
|
||||
|
||||
public FilterInvocation(String contextPath, String servletPath, String pathInfo, String query, String method) {
|
||||
this(contextPath, servletPath, pathInfo, query, method, null);
|
||||
}
|
||||
|
||||
public FilterInvocation(String contextPath, String servletPath, String pathInfo, String query, String method,
|
||||
ServletContext servletContext) {
|
||||
DummyRequest request = new DummyRequest();
|
||||
contextPath = (contextPath != null) ? contextPath : "/cp";
|
||||
request.setContextPath(contextPath);
|
||||
@@ -90,6 +100,7 @@ public class FilterInvocation {
|
||||
request.setPathInfo(pathInfo);
|
||||
request.setQueryString(query);
|
||||
request.setMethod(method);
|
||||
request.setServletContext(servletContext);
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@@ -160,6 +171,8 @@ public class FilterInvocation {
|
||||
|
||||
private String method;
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
private final HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
private final Map<String, String[]> parameters = new LinkedHashMap<>();
|
||||
@@ -290,6 +303,15 @@ public class FilterInvocation {
|
||||
this.parameters.put(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
return this.servletContext;
|
||||
}
|
||||
|
||||
void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class UnsupportedOperationExceptionInvocationHandler implements InvocationHandler {
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.web.access;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* An implementation of {@link WebInvocationPrivilegeEvaluator} which delegates the checks
|
||||
* to an instance of {@link AuthorizationManager}
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public final class AuthorizationManagerWebInvocationPrivilegeEvaluator
|
||||
implements WebInvocationPrivilegeEvaluator, ServletContextAware {
|
||||
|
||||
private final AuthorizationManager<HttpServletRequest> authorizationManager;
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
public AuthorizationManagerWebInvocationPrivilegeEvaluator(
|
||||
AuthorizationManager<HttpServletRequest> authorizationManager) {
|
||||
Assert.notNull(authorizationManager, "authorizationManager cannot be null");
|
||||
this.authorizationManager = authorizationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed(String uri, Authentication authentication) {
|
||||
return isAllowed(null, uri, null, authentication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed(String contextPath, String uri, String method, Authentication authentication) {
|
||||
FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext);
|
||||
AuthorizationDecision decision = this.authorizationManager.check(() -> authentication,
|
||||
filterInvocation.getHttpRequest());
|
||||
return decision == null || decision.isGranted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
}
|
||||
+13
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
* Copyright 2002-2021 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,6 +18,8 @@ package org.springframework.security.web.access;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -28,6 +30,7 @@ import org.springframework.security.access.intercept.AbstractSecurityInterceptor
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* Allows users to determine whether they have privileges for a given web URI.
|
||||
@@ -36,12 +39,14 @@ import org.springframework.util.Assert;
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DefaultWebInvocationPrivilegeEvaluator implements WebInvocationPrivilegeEvaluator {
|
||||
public class DefaultWebInvocationPrivilegeEvaluator implements WebInvocationPrivilegeEvaluator, ServletContextAware {
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(DefaultWebInvocationPrivilegeEvaluator.class);
|
||||
|
||||
private final AbstractSecurityInterceptor securityInterceptor;
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
public DefaultWebInvocationPrivilegeEvaluator(AbstractSecurityInterceptor securityInterceptor) {
|
||||
Assert.notNull(securityInterceptor, "SecurityInterceptor cannot be null");
|
||||
Assert.isTrue(FilterInvocation.class.equals(securityInterceptor.getSecureObjectClass()),
|
||||
@@ -82,7 +87,7 @@ public class DefaultWebInvocationPrivilegeEvaluator implements WebInvocationPriv
|
||||
@Override
|
||||
public boolean isAllowed(String contextPath, String uri, String method, Authentication authentication) {
|
||||
Assert.notNull(uri, "uri parameter is required");
|
||||
FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method);
|
||||
FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext);
|
||||
Collection<ConfigAttribute> attributes = this.securityInterceptor.obtainSecurityMetadataSource()
|
||||
.getAttributes(filterInvocation);
|
||||
if (attributes == null) {
|
||||
@@ -101,4 +106,9 @@ public class DefaultWebInvocationPrivilegeEvaluator implements WebInvocationPriv
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.web.access;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* A {@link WebInvocationPrivilegeEvaluator} which delegates to a list of
|
||||
* {@link WebInvocationPrivilegeEvaluator} based on a
|
||||
* {@link org.springframework.security.web.util.matcher.RequestMatcher} evaluation
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public final class RequestMatcherDelegatingWebInvocationPrivilegeEvaluator
|
||||
implements WebInvocationPrivilegeEvaluator, ServletContextAware {
|
||||
|
||||
private final List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> delegates;
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
public RequestMatcherDelegatingWebInvocationPrivilegeEvaluator(
|
||||
List<RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>>> requestMatcherPrivilegeEvaluatorsEntries) {
|
||||
Assert.notNull(requestMatcherPrivilegeEvaluatorsEntries, "requestMatcherPrivilegeEvaluators cannot be null");
|
||||
for (RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> entry : requestMatcherPrivilegeEvaluatorsEntries) {
|
||||
Assert.notNull(entry.getRequestMatcher(), "requestMatcher cannot be null");
|
||||
Assert.notNull(entry.getEntry(), "webInvocationPrivilegeEvaluators cannot be null");
|
||||
}
|
||||
this.delegates = requestMatcherPrivilegeEvaluatorsEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the user represented by the supplied <tt>Authentication</tt>
|
||||
* object is allowed to invoke the supplied URI.
|
||||
* <p>
|
||||
* Uses the provided URI in the
|
||||
* {@link org.springframework.security.web.util.matcher.RequestMatcher#matches(HttpServletRequest)}
|
||||
* for every {@code RequestMatcher} configured. If no {@code RequestMatcher} is
|
||||
* matched, or if there is not an available {@code WebInvocationPrivilegeEvaluator},
|
||||
* returns {@code true}.
|
||||
* @param uri the URI excluding the context path (a default context path setting will
|
||||
* be used)
|
||||
* @return true if access is allowed, false if denied
|
||||
*/
|
||||
@Override
|
||||
public boolean isAllowed(String uri, Authentication authentication) {
|
||||
List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = getDelegate(null, uri, null);
|
||||
if (privilegeEvaluators.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (WebInvocationPrivilegeEvaluator evaluator : privilegeEvaluators) {
|
||||
boolean isAllowed = evaluator.isAllowed(uri, authentication);
|
||||
if (!isAllowed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the user represented by the supplied <tt>Authentication</tt>
|
||||
* object is allowed to invoke the supplied URI.
|
||||
* <p>
|
||||
* Uses the provided URI in the
|
||||
* {@link org.springframework.security.web.util.matcher.RequestMatcher#matches(HttpServletRequest)}
|
||||
* for every {@code RequestMatcher} configured. If no {@code RequestMatcher} is
|
||||
* matched, or if there is not an available {@code WebInvocationPrivilegeEvaluator},
|
||||
* returns {@code true}.
|
||||
* @param uri the URI excluding the context path (a default context path setting will
|
||||
* be used)
|
||||
* @param contextPath the context path (may be null, in which case a default value
|
||||
* will be used).
|
||||
* @param method the HTTP method (or null, for any method)
|
||||
* @param authentication the <tt>Authentication</tt> instance whose authorities should
|
||||
* be used in evaluation whether access should be granted.
|
||||
* @return true if access is allowed, false if denied
|
||||
*/
|
||||
@Override
|
||||
public boolean isAllowed(String contextPath, String uri, String method, Authentication authentication) {
|
||||
List<WebInvocationPrivilegeEvaluator> privilegeEvaluators = getDelegate(contextPath, uri, method);
|
||||
if (privilegeEvaluators.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (WebInvocationPrivilegeEvaluator evaluator : privilegeEvaluators) {
|
||||
boolean isAllowed = evaluator.isAllowed(contextPath, uri, method, authentication);
|
||||
if (!isAllowed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<WebInvocationPrivilegeEvaluator> getDelegate(String contextPath, String uri, String method) {
|
||||
FilterInvocation filterInvocation = new FilterInvocation(contextPath, uri, method, this.servletContext);
|
||||
for (RequestMatcherEntry<List<WebInvocationPrivilegeEvaluator>> delegate : this.delegates) {
|
||||
if (delegate.getRequestMatcher().matches(filterInvocation.getHttpRequest())) {
|
||||
return delegate.getEntry();
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
}
|
||||
+9
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -67,4 +67,12 @@ public class AuthorizationFilter extends OncePerRequestFilter {
|
||||
return authentication;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link AuthorizationManager} used by this filter
|
||||
* @return the {@link AuthorizationManager}
|
||||
*/
|
||||
public AuthorizationManager<HttpServletRequest> getAuthorizationManager() {
|
||||
return this.authorizationManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -78,11 +78,11 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
* @deprecated Use
|
||||
* {@link org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver}
|
||||
* instead.
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
@Deprecated
|
||||
public final class AuthenticationPrincipalArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2021 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,7 +26,7 @@ package org.springframework.security.web.csrf;
|
||||
public class MissingCsrfTokenException extends CsrfException {
|
||||
|
||||
public MissingCsrfTokenException(String actualToken) {
|
||||
super("Could not verify the provided CSRF token because your session was not found.");
|
||||
super("Could not verify the provided CSRF token because no token was found to compare.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -151,6 +151,10 @@ public final class DebugFilter implements Filter {
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
public FilterChainProxy getFilterChainProxy() {
|
||||
return this.filterChainProxy;
|
||||
}
|
||||
|
||||
static class DebugRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private static final Logger logger = new Logger();
|
||||
|
||||
@@ -29,9 +29,9 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see WebServletJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonDeserialize(using = CookieDeserializer.class)
|
||||
|
||||
+1
-1
@@ -31,9 +31,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see WebJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
|
||||
+1
-1
@@ -34,9 +34,9 @@ import org.springframework.security.web.savedrequest.DefaultSavedRequest;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see WebServletJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonDeserialize(builder = DefaultSavedRequest.Builder.class)
|
||||
|
||||
+1
-1
@@ -42,9 +42,9 @@ import org.springframework.security.jackson2.SimpleGrantedAuthorityMixin;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see Webackson2Module
|
||||
* @see SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
|
||||
@@ -33,9 +33,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh.
|
||||
* @since 4.2
|
||||
* @see WebServletJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
|
||||
+1
-1
@@ -32,9 +32,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jitendra Singh
|
||||
* @since 4.2
|
||||
* @see WebServletJackson2Module
|
||||
* @see org.springframework.security.jackson2.SecurityJackson2Modules
|
||||
* @since 4.2
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
|
||||
+11
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.security.web.server.header;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -41,8 +40,16 @@ public class StaticServerHttpHeadersWriter implements ServerHttpHeadersWriter {
|
||||
@Override
|
||||
public Mono<Void> writeHttpHeaders(ServerWebExchange exchange) {
|
||||
HttpHeaders headers = exchange.getResponse().getHeaders();
|
||||
boolean containsOneHeaderToAdd = Collections.disjoint(headers.keySet(), this.headersToAdd.keySet());
|
||||
if (containsOneHeaderToAdd) {
|
||||
// Note: We need to ensure that the following algorithm compares headers
|
||||
// case insensitively, which should be true of headers.containsKey().
|
||||
boolean containsNoHeadersToAdd = true;
|
||||
for (String headerName : this.headersToAdd.keySet()) {
|
||||
if (headers.containsKey(headerName)) {
|
||||
containsNoHeadersToAdd = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (containsNoHeadersToAdd) {
|
||||
this.headersToAdd.forEach(headers::put);
|
||||
}
|
||||
return Mono.empty();
|
||||
|
||||
+1
-1
@@ -32,8 +32,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
* </pre>
|
||||
*
|
||||
* @author Boris Finkelshteyn
|
||||
* @see WebServerJackson2Module
|
||||
* @since 5.1
|
||||
* @see WebServerJackson2Module
|
||||
*/
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -66,7 +66,7 @@ public class MediaTypeServerWebExchangeMatcher implements ServerWebExchangeMatch
|
||||
*/
|
||||
public MediaTypeServerWebExchangeMatcher(Collection<MediaType> matchingMediaTypes) {
|
||||
Assert.notEmpty(matchingMediaTypes, "matchingMediaTypes cannot be null");
|
||||
Assert.isTrue(!matchingMediaTypes.contains(null),
|
||||
Assert.noNullElements(matchingMediaTypes,
|
||||
() -> "matchingMediaTypes cannot contain null. Got " + matchingMediaTypes);
|
||||
this.matchingMediaTypes = matchingMediaTypes;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -45,7 +45,7 @@ public final class AndRequestMatcher implements RequestMatcher {
|
||||
*/
|
||||
public AndRequestMatcher(List<RequestMatcher> requestMatchers) {
|
||||
Assert.notEmpty(requestMatchers, "requestMatchers must contain a value");
|
||||
Assert.isTrue(!requestMatchers.contains(null), "requestMatchers cannot contain null values");
|
||||
Assert.noNullElements(requestMatchers, "requestMatchers cannot contain null values");
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ import org.springframework.web.util.UrlPathHelper;
|
||||
* @author Rob Winch
|
||||
* @author Eddú Meléndez
|
||||
* @author Evgeniy Cheban
|
||||
* @author Manuel Jordan
|
||||
* @since 3.1
|
||||
* @see org.springframework.util.AntPathMatcher
|
||||
*/
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2022 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.
|
||||
@@ -40,7 +40,7 @@ public final class OrRequestMatcher implements RequestMatcher {
|
||||
*/
|
||||
public OrRequestMatcher(List<RequestMatcher> requestMatchers) {
|
||||
Assert.notEmpty(requestMatchers, "requestMatchers must contain a value");
|
||||
Assert.isTrue(!requestMatchers.contains(null), "requestMatchers cannot contain null values");
|
||||
Assert.noNullElements(requestMatchers, "requestMatchers cannot contain null values");
|
||||
this.requestMatchers = requestMatchers;
|
||||
}
|
||||
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.web.util.matcher;
|
||||
|
||||
/**
|
||||
* A rich object for associating a {@link RequestMatcher} to another object.
|
||||
*
|
||||
* @author Marcus Da Coregio
|
||||
* @since 5.5.5
|
||||
*/
|
||||
public class RequestMatcherEntry<T> {
|
||||
|
||||
private final RequestMatcher requestMatcher;
|
||||
|
||||
private final T entry;
|
||||
|
||||
public RequestMatcherEntry(RequestMatcher requestMatcher, T entry) {
|
||||
this.requestMatcher = requestMatcher;
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
public RequestMatcher getRequestMatcher() {
|
||||
return this.requestMatcher;
|
||||
}
|
||||
|
||||
public T getEntry() {
|
||||
return this.entry;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
* Copyright 2002-2021 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,7 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.web.FilterInvocation.DummyRequest;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
|
||||
@@ -131,4 +132,14 @@ public class FilterInvocationTests {
|
||||
UrlUtils.buildRequestUrl(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenServletContextProvidedThenSetServletContextInRequest() {
|
||||
String contextPath = "";
|
||||
String servletPath = "/path";
|
||||
String method = "";
|
||||
MockServletContext mockServletContext = new MockServletContext();
|
||||
FilterInvocation filterInvocation = new FilterInvocation(contextPath, servletPath, method, mockServletContext);
|
||||
assertThat(filterInvocation.getRequest().getServletContext()).isSameAs(mockServletContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.web.access;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.AuthorizationManager;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AuthorizationManagerWebInvocationPrivilegeEvaluatorTests {
|
||||
|
||||
@InjectMocks
|
||||
private AuthorizationManagerWebInvocationPrivilegeEvaluator privilegeEvaluator;
|
||||
|
||||
@Mock
|
||||
private AuthorizationManager<HttpServletRequest> authorizationManager;
|
||||
|
||||
@Test
|
||||
public void constructorWhenAuthorizationManagerNullThenIllegalArgument() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new AuthorizationManagerWebInvocationPrivilegeEvaluator(null))
|
||||
.withMessage("authorizationManager cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAllowedWhenAuthorizationManagerAllowsThenAllowedTrue() {
|
||||
given(this.authorizationManager.check(any(), any())).willReturn(new AuthorizationDecision(true));
|
||||
boolean allowed = this.privilegeEvaluator.isAllowed("/test", TestAuthentication.authenticatedUser());
|
||||
assertThat(allowed).isTrue();
|
||||
verify(this.authorizationManager).check(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAllowedWhenAuthorizationManagerDeniesAllowedFalse() {
|
||||
given(this.authorizationManager.check(any(), any())).willReturn(new AuthorizationDecision(false));
|
||||
boolean allowed = this.privilegeEvaluator.isAllowed("/test", TestAuthentication.authenticatedUser());
|
||||
assertThat(allowed).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAllowedWhenAuthorizationManagerAbstainsThenAllowedTrue() {
|
||||
given(this.authorizationManager.check(any(), any())).willReturn(null);
|
||||
boolean allowed = this.privilegeEvaluator.isAllowed("/test", TestAuthentication.authenticatedUser());
|
||||
assertThat(allowed).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAllowedWhenServletContextExistsThenFilterInvocationHasServletContext() {
|
||||
ServletContext servletContext = new MockServletContext();
|
||||
this.privilegeEvaluator.setServletContext(servletContext);
|
||||
this.privilegeEvaluator.isAllowed("/test", TestAuthentication.authenticatedUser());
|
||||
ArgumentCaptor<HttpServletRequest> captor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
||||
verify(this.authorizationManager).check(any(), captor.capture());
|
||||
assertThat(captor.getValue().getServletContext()).isSameAs(servletContext);
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -18,8 +18,10 @@ package org.springframework.security.web.access;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.access.intercept.RunAsManager;
|
||||
@@ -27,6 +29,7 @@ import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
|
||||
@@ -34,9 +37,11 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.anyObject;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.willThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests
|
||||
@@ -106,4 +111,17 @@ public class DefaultWebInvocationPrivilegeEvaluatorTests {
|
||||
assertThat(wipe.isAllowed("/foo/index.jsp", token)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAllowedWhenServletContextIsSetThenPassedFilterInvocationHasServletContext() {
|
||||
Authentication token = new TestingAuthenticationToken("test", "Password", "MOCK_INDEX");
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
ArgumentCaptor<FilterInvocation> filterInvocationArgumentCaptor = ArgumentCaptor
|
||||
.forClass(FilterInvocation.class);
|
||||
DefaultWebInvocationPrivilegeEvaluator wipe = new DefaultWebInvocationPrivilegeEvaluator(this.interceptor);
|
||||
wipe.setServletContext(servletContext);
|
||||
wipe.isAllowed("/foo/index.jsp", token);
|
||||
verify(this.adm).decide(eq(token), filterInvocationArgumentCaptor.capture(), any());
|
||||
assertThat(filterInvocationArgumentCaptor.getValue().getRequest().getServletContext()).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user