diff --git a/.travis.yml b/.travis.yml
index 9fc2c78e84b..981df90b0af 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
language: java
jdk:
- - oraclejdk8
+ - openjdk8
os:
- linux
diff --git a/Jenkinsfile b/Jenkinsfile
index 88c32258ba0..4c6c3d9a194 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -14,7 +14,9 @@ try {
node {
checkout scm
try {
- sh "./gradlew clean check --refresh-dependencies --no-daemon --stacktrace"
+ withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
+ sh "./gradlew clean check --refresh-dependencies --no-daemon --stacktrace"
+ }
} catch(Exception e) {
currentBuild.result = 'FAILED: check'
throw e
@@ -30,10 +32,12 @@ try {
checkout scm
withCredentials([string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')]) {
try {
- if ("master" == env.BRANCH_NAME) {
- sh "./gradlew sonarqube -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon --stacktrace"
- } else {
- sh "./gradlew sonarqube -PexcludeProjects='**/samples/**' -Dsonar.projectKey='spring-security-${env.BRANCH_NAME}' -Dsonar.projectName='spring-security-${env.BRANCH_NAME}' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon --stacktrace"
+ withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
+ if ("master" == env.BRANCH_NAME) {
+ sh "./gradlew sonarqube -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon --stacktrace"
+ } else {
+ sh "./gradlew sonarqube -PexcludeProjects='**/samples/**' -Dsonar.projectKey='spring-security-${env.BRANCH_NAME}' -Dsonar.projectName='spring-security-${env.BRANCH_NAME}' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon --stacktrace"
+ }
}
} catch(Exception e) {
currentBuild.result = 'FAILED: sonar'
@@ -48,7 +52,9 @@ try {
node {
checkout scm
try {
- sh "./gradlew clean test -PforceMavenRepositories=snapshot -PspringVersion='5.+' -PreactorVersion=Californium-BUILD-SNAPSHOT -PspringDataVersion=Lovelace-BUILD-SNAPSHOT --refresh-dependencies --no-daemon --stacktrace"
+ withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
+ sh "./gradlew clean test -PforceMavenRepositories=snapshot -PspringVersion='5.1.+' -PreactorVersion=Californium-BUILD-SNAPSHOT -PspringDataVersion=Lovelace-BUILD-SNAPSHOT --refresh-dependencies --no-daemon --stacktrace"
+ }
} catch(Exception e) {
currentBuild.result = 'FAILED: snapshots'
throw e
@@ -111,7 +117,9 @@ try {
withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) {
withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) {
withCredentials([usernamePassword(credentialsId: '02bd1690-b54f-4c9f-819d-a77cb7a9822c', usernameVariable: 'ARTIFACTORY_USERNAME', passwordVariable: 'ARTIFACTORY_PASSWORD')]) {
- sh "./gradlew deployArtifacts finalizeDeployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --refresh-dependencies --no-daemon --stacktrace"
+ withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
+ sh "./gradlew deployArtifacts finalizeDeployArtifacts -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password='$SIGNING_PASSWORD' -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD -PartifactoryUsername=$ARTIFACTORY_USERNAME -PartifactoryPassword=$ARTIFACTORY_PASSWORD --refresh-dependencies --no-daemon --stacktrace"
+ }
}
}
}
@@ -124,7 +132,9 @@ try {
node {
checkout scm
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
- sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
+ withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
+ sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
+ }
}
}
}
@@ -134,7 +144,9 @@ try {
node {
checkout scm
withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) {
- sh "./gradlew deploySchema -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
+ withEnv(["JAVA_HOME=${ tool 'jdk8' }"]) {
+ sh "./gradlew deploySchema -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace"
+ }
}
}
}
diff --git a/acl/src/main/java/org/springframework/security/acls/domain/AccessControlEntryImpl.java b/acl/src/main/java/org/springframework/security/acls/domain/AccessControlEntryImpl.java
index f39dbd30b54..fb41f101d6c 100644
--- a/acl/src/main/java/org/springframework/security/acls/domain/AccessControlEntryImpl.java
+++ b/acl/src/main/java/org/springframework/security/acls/domain/AccessControlEntryImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+ * Copyright 2002-2016 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.
@@ -131,10 +131,9 @@ public boolean equals(Object arg0) {
@Override
public int hashCode() {
- int result = this.acl.hashCode();
- result = 31 * result + this.permission.hashCode();
+ int result = this.permission.hashCode();
result = 31 * result + (this.id != null ? this.id.hashCode() : 0);
- result = 31 * result + this.sid.hashCode();
+ result = 31 * result + (this.sid.hashCode());
result = 31 * result + (this.auditFailure ? 1 : 0);
result = 31 * result + (this.auditSuccess ? 1 : 0);
result = 31 * result + (this.granting ? 1 : 0);
diff --git a/acl/src/test/java/org/springframework/security/acls/domain/AclImplTests.java b/acl/src/test/java/org/springframework/security/acls/domain/AclImplTests.java
index 1362a45f98e..c14292bb1f9 100644
--- a/acl/src/test/java/org/springframework/security/acls/domain/AclImplTests.java
+++ b/acl/src/test/java/org/springframework/security/acls/domain/AclImplTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -560,6 +560,25 @@ public void changingParentIsSuccessful() throws Exception {
childAcl.setParent(changeParentAcl);
}
+ @Test
+ public void hashCodeWithoutStackOverFlow() throws Exception {
+ //given
+ Sid sid = new PrincipalSid("pSid");
+ ObjectIdentity oid = new ObjectIdentityImpl("type", 1);
+ AclAuthorizationStrategy authStrategy = new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("role"));
+ PermissionGrantingStrategy grantingStrategy = new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
+
+ AclImpl acl = new AclImpl(oid, 1L, authStrategy, grantingStrategy, null, null, false, sid);
+ AccessControlEntryImpl ace = new AccessControlEntryImpl(1L, acl, sid, BasePermission.READ, true, true, true);
+
+ Field fieldAces = FieldUtils.getField(AclImpl.class, "aces");
+ fieldAces.setAccessible(true);
+ List aces = (List) fieldAces.get(acl);
+ aces.add(ace);
+ //when - then none StackOverFlowError been raised
+ ace.hashCode();
+ }
+
// ~ Inner Classes
// ==================================================================================================
diff --git a/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetailsSource.java b/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetailsSource.java
index 63613d8fe6c..c323bb491b7 100644
--- a/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetailsSource.java
+++ b/cas/src/main/java/org/springframework/security/cas/web/authentication/ServiceAuthenticationDetailsSource.java
@@ -47,7 +47,7 @@ public class ServiceAuthenticationDetailsSource implements
// ===================================================================================================
/**
- * Creates an implementation that uses the specified ServiceProperites and the default
+ * Creates an implementation that uses the specified ServiceProperties and the default
* CAS artifactParameterName.
*
* @param serviceProperties The ServiceProperties to use to construct the serviceUrl.
diff --git a/config/src/main/java/org/springframework/security/config/annotation/configuration/ObjectPostProcessorConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/configuration/ObjectPostProcessorConfiguration.java
index 1e681b1670e..cd7e8680b67 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/configuration/ObjectPostProcessorConfiguration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/configuration/ObjectPostProcessorConfiguration.java
@@ -16,8 +16,10 @@
package org.springframework.security.config.annotation.configuration;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Role;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -34,9 +36,11 @@
* @since 3.2
*/
@Configuration
+@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ObjectPostProcessorConfiguration {
@Bean
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ObjectPostProcessor objectPostProcessor(
AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java
index 1639eeb4047..7c73ab55d3d 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java
@@ -31,8 +31,10 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
+import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
@@ -83,6 +85,7 @@
* @see EnableGlobalMethodSecurity
*/
@Configuration
+@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class GlobalMethodSecurityConfiguration
implements ImportAware, SmartInitializingSingleton, BeanFactoryAware {
private static final Log logger = LogFactory
diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MetadataSourceConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MetadataSourceConfiguration.java
index e8786c27614..79e74eaf8fc 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MetadataSourceConfiguration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MetadataSourceConfiguration.java
@@ -15,14 +15,18 @@
*/
package org.springframework.security.config.annotation.method.configuration;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Role;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
@Configuration
+@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
class Jsr250MetadataSourceConfiguration {
@Bean
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public Jsr250MethodSecurityMetadataSource jsr250MethodSecurityMetadataSource() {
return new Jsr250MethodSecurityMetadataSource();
}
diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfiguration.java
index f6d9aa6cce8..53a839f460f 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfiguration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfiguration.java
@@ -49,6 +49,7 @@ public MethodSecurityMetadataSourceAdvisor methodSecurityInterceptor(AbstractMet
}
@Bean
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public DelegatingMethodSecurityMetadataSource methodMetadataSource() {
ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(
new DefaultMethodSecurityExpressionHandler());
@@ -69,6 +70,7 @@ public PrePostAdviceReactiveMethodInterceptor securityMethodInterceptor(Abstract
}
@Bean
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler() {
return new DefaultMethodSecurityExpressionHandler();
}
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
index db5151c521b..a29bf42c9b9 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
@@ -586,6 +586,7 @@ public RememberMeConfigurer rememberMe() throws Exception {
/**
* Allows restricting access based upon the {@link HttpServletRequest} using
+ * {@link RequestMatcher} implementations (i.e. via URL patterns).
*
* Example Configurations
*
@@ -723,7 +724,7 @@ public ServletApiConfigurer servletApi() throws Exception {
* }
*
*
- * @return the {@link ServletApiConfigurer} for further customizations
+ * @return the {@link CsrfConfigurer} for further customizations
* @throws Exception
*/
public CsrfConfigurer csrf() throws Exception {
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractAuthenticationFilterConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractAuthenticationFilterConfigurer.java
index 8598e71507c..f56bfdb9a61 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractAuthenticationFilterConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractAuthenticationFilterConfigurer.java
@@ -171,7 +171,7 @@ public final T authenticationDetailsSource(
/**
* Specifies the {@link AuthenticationSuccessHandler} to be used. The default is
- * {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properites
+ * {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properties
* set.
*
* @param successHandler the {@link AuthenticationSuccessHandler}.
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java
index 83e88c5252f..6b2cc72d653 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
-import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
@@ -64,6 +63,7 @@
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -429,9 +429,6 @@ public void init(B http) throws Exception {
this.loginProcessingUrl);
this.setAuthenticationFilter(authenticationFilter);
super.loginProcessingUrl(this.loginProcessingUrl);
- RequestMatcher authenticationNullMatcher = request -> SecurityContextHolder.getContext().getAuthentication() == null;
- authenticationFilter.setRequiresAuthenticationRequestMatcher(new AndRequestMatcher(createLoginProcessingUrlMatcher(this.loginProcessingUrl),
- authenticationNullMatcher));
if (this.loginPage != null) {
// Set custom login page
@@ -604,8 +601,11 @@ private AuthenticationEntryPoint getLoginEntryPoint(B http, String providerLogin
RequestMatcher defaultLoginPageMatcher = new AndRequestMatcher(
new OrRequestMatcher(loginPageMatcher, faviconMatcher), defaultEntryPointMatcher);
+ RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
+ new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
+
LinkedHashMap entryPoints = new LinkedHashMap<>();
- entryPoints.put(new NegatedRequestMatcher(defaultLoginPageMatcher),
+ entryPoints.put(new AndRequestMatcher(notXRequestedWith, new NegatedRequestMatcher(defaultLoginPageMatcher)),
new LoginUrlAuthenticationEntryPoint(providerLoginPage));
DelegatingAuthenticationEntryPoint loginEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java
index 490dc7f597d..e203194ed5d 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurer.java
@@ -160,6 +160,25 @@ public JwtConfigurer jwt() {
@Override
public void init(H http) throws Exception {
+ if ( this.jwtConfigurer == null ) {
+ throw new IllegalStateException("Jwt is the only supported format for bearer tokens " +
+ "in Spring Security and no Jwt configuration was found. Make sure to specify " +
+ "a jwk set uri by doing http.oauth2ResourceServer().jwt().jwkSetUri(uri), or wire a " +
+ "JwtDecoder instance by doing http.oauth2ResourceServer().jwt().decoder(decoder), or " +
+ "expose a JwtDecoder instance as a bean and do http.oauth2ResourceServer().jwt().");
+ }
+
+ JwtDecoder decoder = this.jwtConfigurer.getJwtDecoder();
+ Converter jwtAuthenticationConverter =
+ this.jwtConfigurer.getJwtAuthenticationConverter();
+
+ JwtAuthenticationProvider provider =
+ new JwtAuthenticationProvider(decoder);
+ provider.setJwtAuthenticationConverter(jwtAuthenticationConverter);
+ provider = postProcess(provider);
+
+ http.authenticationProvider(provider);
+
registerDefaultAccessDeniedHandler(http);
registerDefaultEntryPoint(http);
registerDefaultCsrfOverride(http);
@@ -179,25 +198,6 @@ public void configure(H http) throws Exception {
filter = postProcess(filter);
http.addFilter(filter);
-
- if ( this.jwtConfigurer == null ) {
- throw new IllegalStateException("Jwt is the only supported format for bearer tokens " +
- "in Spring Security and no Jwt configuration was found. Make sure to specify " +
- "a jwk set uri by doing http.oauth2ResourceServer().jwt().jwkSetUri(uri), or wire a " +
- "JwtDecoder instance by doing http.oauth2ResourceServer().jwt().decoder(decoder), or " +
- "expose a JwtDecoder instance as a bean and do http.oauth2ResourceServer().jwt().");
- }
-
- JwtDecoder decoder = this.jwtConfigurer.getJwtDecoder();
- Converter jwtAuthenticationConverter =
- this.jwtConfigurer.getJwtAuthenticationConverter();
-
- JwtAuthenticationProvider provider =
- new JwtAuthenticationProvider(decoder);
- provider.setJwtAuthenticationConverter(jwtAuthenticationConverter);
- provider = postProcess(provider);
-
- http.authenticationProvider(provider);
}
public class JwtConfigurer {
diff --git a/config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java
index 7755c85a51b..062d0815edc 100644
--- a/config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java
+++ b/config/src/main/java/org/springframework/security/config/method/GlobalMethodSecurityBeanDefinitionParser.java
@@ -208,7 +208,7 @@ public BeanDefinition parse(Element element, ParserContext pc) {
pc.registerBeanComponent(new BeanComponentDefinition(
expressionHandler, expressionHandlerRef));
logger.info("Expressions were enabled for method security but no SecurityExpressionHandler was configured. "
- + "All hasPermision() expressions will evaluate to false.");
+ + "All hasPermission() expressions will evaluate to false.");
}
BeanDefinitionBuilder expressionPreAdviceBldr = BeanDefinitionBuilder
diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java
index ec5f578ca66..95db5745dfd 100644
--- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java
+++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -53,8 +53,6 @@
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeReactiveAuthenticationManager;
@@ -90,7 +88,6 @@
import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
-import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationEntryPoint;
@@ -620,38 +617,62 @@ protected void configure(ServerHttpSecurity http) {
AuthenticationWebFilter authenticationFilter = new OAuth2LoginAuthenticationWebFilter(manager, authorizedClientRepository);
authenticationFilter.setRequiresAuthenticationMatcher(createAttemptAuthenticationRequestMatcher());
authenticationFilter.setServerAuthenticationConverter(getAuthenticationConverter(clientRegistrationRepository));
- RedirectServerAuthenticationSuccessHandler redirectHandler = new RedirectServerAuthenticationSuccessHandler();
-
- authenticationFilter.setAuthenticationSuccessHandler(redirectHandler);
- authenticationFilter.setAuthenticationFailureHandler(new ServerAuthenticationFailureHandler() {
- @Override
- public Mono onAuthenticationFailure(WebFilterExchange webFilterExchange,
- AuthenticationException exception) {
- return Mono.error(exception);
- }
- });
+ authenticationFilter.setAuthenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler());
+ authenticationFilter.setAuthenticationFailureHandler(new RedirectServerAuthenticationFailureHandler("/login?error"));
authenticationFilter.setSecurityContextRepository(new WebSessionServerSecurityContextRepository());
- MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher(
- MediaType.TEXT_HTML);
- htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
+ setDefaultEntryPoints(http);
+
+ http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
+ http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
+ }
+
+ private void setDefaultEntryPoints(ServerHttpSecurity http) {
+ String defaultLoginPage = "/login";
Map urlToText = http.oauth2Login.getLinks();
+ String providerLoginPage = null;
if (urlToText.size() == 1) {
- http.defaultEntryPoints.add(new DelegateEntry(htmlMatcher, new RedirectServerAuthenticationEntryPoint(urlToText.keySet().iterator().next())));
- } else {
- http.defaultEntryPoints.add(new DelegateEntry(htmlMatcher, new RedirectServerAuthenticationEntryPoint("/login")));
+ providerLoginPage = urlToText.keySet().iterator().next();
}
- http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
- http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
+ MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher(
+ MediaType.APPLICATION_XHTML_XML, new MediaType("image", "*"),
+ MediaType.TEXT_HTML, MediaType.TEXT_PLAIN);
+ htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
+
+ ServerWebExchangeMatcher xhrMatcher = exchange -> {
+ if (exchange.getRequest().getHeaders().getOrDefault("X-Requested-With", Collections.emptyList()).contains("XMLHttpRequest")) {
+ return ServerWebExchangeMatcher.MatchResult.match();
+ }
+ return ServerWebExchangeMatcher.MatchResult.notMatch();
+ };
+ ServerWebExchangeMatcher notXhrMatcher = new NegatedServerWebExchangeMatcher(xhrMatcher);
+
+ ServerWebExchangeMatcher defaultEntryPointMatcher = new AndServerWebExchangeMatcher(
+ notXhrMatcher, htmlMatcher);
+
+ if (providerLoginPage != null) {
+ ServerWebExchangeMatcher loginPageMatcher = new PathPatternParserServerWebExchangeMatcher(defaultLoginPage);
+ ServerWebExchangeMatcher faviconMatcher = new PathPatternParserServerWebExchangeMatcher("/favicon.ico");
+ ServerWebExchangeMatcher defaultLoginPageMatcher = new AndServerWebExchangeMatcher(
+ new OrServerWebExchangeMatcher(loginPageMatcher, faviconMatcher), defaultEntryPointMatcher);
+
+ ServerWebExchangeMatcher matcher = new AndServerWebExchangeMatcher(
+ notXhrMatcher, new NegatedServerWebExchangeMatcher(defaultLoginPageMatcher));
+ RedirectServerAuthenticationEntryPoint entryPoint =
+ new RedirectServerAuthenticationEntryPoint(providerLoginPage);
+ entryPoint.setRequestCache(http.requestCache.requestCache);
+ http.defaultEntryPoints.add(new DelegateEntry(matcher, entryPoint));
+ }
+
+ RedirectServerAuthenticationEntryPoint defaultEntryPoint =
+ new RedirectServerAuthenticationEntryPoint(defaultLoginPage);
+ defaultEntryPoint.setRequestCache(http.requestCache.requestCache);
+ http.defaultEntryPoints.add(new DelegateEntry(defaultEntryPointMatcher, defaultEntryPoint));
}
private ServerWebExchangeMatcher createAttemptAuthenticationRequestMatcher() {
- PathPatternParserServerWebExchangeMatcher loginPathMatcher = new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}");
- ServerWebExchangeMatcher notAuthenticatedMatcher = e -> ReactiveSecurityContextHolder.getContext()
- .flatMap(p -> ServerWebExchangeMatcher.MatchResult.notMatch())
- .switchIfEmpty(ServerWebExchangeMatcher.MatchResult.match());
- return new AndServerWebExchangeMatcher(loginPathMatcher, notAuthenticatedMatcher);
+ return new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}");
}
private ReactiveOAuth2UserService getOidcUserService() {
@@ -1282,11 +1303,15 @@ public SecurityWebFilterChain build() {
this.cors.configure(this);
}
if (this.httpBasic != null) {
- this.httpBasic.authenticationManager(this.authenticationManager);
+ if (this.httpBasic.authenticationManager == null) {
+ this.httpBasic.authenticationManager(this.authenticationManager);
+ }
this.httpBasic.configure(this);
}
if (this.formLogin != null) {
- this.formLogin.authenticationManager(this.authenticationManager);
+ if (this.formLogin.authenticationManager == null) {
+ this.formLogin.authenticationManager(this.authenticationManager);
+ }
if (this.securityContextRepository != null) {
this.formLogin.securityContextRepository(this.securityContextRepository);
}
@@ -1478,7 +1503,7 @@ public AuthorizeExchangeSpec hasRole(String role) {
/**
* Require a specific authority.
- * @param authority the authority to require (i.e. "USER" woudl require authority of "USER").
+ * @param authority the authority to require (i.e. "USER" would require authority of "USER").
* @return the {@link AuthorizeExchangeSpec} to configure
*/
public AuthorizeExchangeSpec hasAuthority(String authority) {
@@ -2387,7 +2412,9 @@ private HeaderSpec() {
*/
public final class LogoutSpec {
private LogoutWebFilter logoutWebFilter = new LogoutWebFilter();
- private List logoutHandlers = new ArrayList<>(Arrays.asList(new SecurityContextServerLogoutHandler()));
+ private final SecurityContextServerLogoutHandler DEFAULT_LOGOUT_HANDLER = new SecurityContextServerLogoutHandler();
+ private List logoutHandlers = new ArrayList<>(Arrays.asList(this.DEFAULT_LOGOUT_HANDLER));
+
/**
* Configures the logout handler. Default is {@code SecurityContextServerLogoutHandler}
@@ -2451,6 +2478,10 @@ public ServerHttpSecurity disable() {
}
private Optional createLogoutHandler() {
+ ServerSecurityContextRepository securityContextRepository = ServerHttpSecurity.this.securityContextRepository;
+ if (securityContextRepository != null) {
+ this.DEFAULT_LOGOUT_HANDLER.setSecurityContextRepository(securityContextRepository);
+ }
if (this.logoutHandlers.isEmpty()) {
return Optional.empty();
}
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java
index 3031dde48ce..e8b6741d438 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurerTests.java
@@ -28,7 +28,6 @@
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
-import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -38,7 +37,6 @@
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
-import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
@@ -182,31 +180,6 @@ public void oauth2LoginWhenSuccessThenAuthenticationSuccessEventPublished() thro
assertThat(OAuth2LoginConfig.EVENTS.get(0)).isInstanceOf(AuthenticationSuccessEvent.class);
}
- @Test
- public void oauth2LoginWhenAuthenticatedThenIgnored() throws Exception {
- // setup application context
- loadConfig(OAuth2LoginConfig.class);
-
- // authenticate
- TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken("a",
- "b", "ROLE_TEST");
-
- this.request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, new SecurityContextImpl(expectedAuthentication));
-
- // setup authentication parameters
- this.request.setParameter("code", "code123");
- this.request.setParameter("state", "state");
-
- // perform test
- this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
-
- // assertions
- Authentication authentication = this.securityContextRepository
- .loadContext(new HttpRequestResponseHolder(this.request, this.response))
- .getAuthentication();
- assertThat(authentication).isEqualTo(expectedAuthentication);
- }
-
@Test
public void oauth2LoginCustomWithConfigurer() throws Exception {
// setup application context
@@ -353,6 +326,21 @@ public void oauth2LoginWithMultipleClientsConfiguredThenRedirectDefaultLoginPage
assertThat(this.response.getRedirectedUrl()).matches("http://localhost/login");
}
+ // gh-6812
+ @Test
+ public void oauth2LoginWithOneClientConfiguredAndRequestXHRNotAuthenticatedThenDoesNotRedirectForAuthorization() throws Exception {
+ loadConfig(OAuth2LoginConfig.class);
+
+ String requestUri = "/";
+ this.request = new MockHttpServletRequest("GET", requestUri);
+ this.request.setServletPath(requestUri);
+ this.request.addHeader("X-Requested-With", "XMLHttpRequest");
+
+ this.springSecurityFilterChain.doFilter(this.request, this.response, this.filterChain);
+
+ assertThat(this.response.getRedirectedUrl()).doesNotMatch("http://localhost/oauth2/authorization/google");
+ }
+
@Test
public void oauth2LoginWithCustomLoginPageThenRedirectCustomLoginPage() throws Exception {
loadConfig(OAuth2LoginConfigCustomLoginPage.class);
diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
index 99cde97018a..3d7558467ec 100644
--- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
+++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java
@@ -298,6 +298,18 @@ public void postWhenCsrfDisabledWithBearerTokenAsFormParameterThenIgnoresToken()
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer"));
}
+ // gh-8031
+ @Test
+ public void getWhenAnonymousDisabledThenAllows() throws Exception {
+ this.spring.register(JwtDecoderConfig.class, AnonymousDisabledConfig.class).autowire();
+ JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
+ when(decoder.decode(anyString())).thenReturn(JWT);
+
+ this.mvc.perform(get("/authenticated")
+ .with(bearerToken("token")))
+ .andExpect(status().isNotFound());
+ }
+
@Test
public void getWhenUsingDefaultsWithNoBearerTokenThenUnauthorized()
throws Exception {
@@ -652,7 +664,8 @@ public void getBearerTokenResolverWhenDuplicateResolverBeansAndAnotherOnTheDslTh
@Test
public void getBearerTokenResolverWhenDuplicateResolverBeansThenWiringException() {
- assertThatCode(() -> this.spring.register(MultipleBearerTokenResolverBeansConfig.class).autowire())
+ assertThatCode(() -> this.spring
+ .register(JwtDecoderConfig.class, MultipleBearerTokenResolverBeansConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class);
}
@@ -1097,6 +1110,22 @@ protected void configure(HttpSecurity http) throws Exception {
}
}
+ @EnableWebSecurity
+ static class AnonymousDisabledConfig extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .anonymous().disable()
+ .oauth2ResourceServer()
+ .jwt();
+ // @formatter:on
+ }
+ }
+
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityConfig extends WebSecurityConfigurerAdapter {
diff --git a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java
index cbf1a2782b0..96a174f3b69 100644
--- a/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java
+++ b/config/src/test/java/org/springframework/security/config/web/server/FormLoginTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,8 @@
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
+import org.springframework.security.authentication.ReactiveAuthenticationManager;
+import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.web.reactive.ServerHttpSecurityConfigurationBuilder;
import org.springframework.security.htmlunit.server.WebTestClientHtmlUnitDriverBuilder;
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
@@ -40,6 +42,10 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyZeroInteractions;
/**
* @author Rob Winch
@@ -152,6 +158,42 @@ public void authenticationSuccess() {
assertThat(driver.getCurrentUrl()).endsWith("/custom");
}
+ @Test
+ public void customAuthenticationManager() {
+ ReactiveAuthenticationManager defaultAuthenticationManager = mock(ReactiveAuthenticationManager.class);
+ ReactiveAuthenticationManager customAuthenticationManager = mock(ReactiveAuthenticationManager.class);
+
+ given(defaultAuthenticationManager.authenticate(any())).willThrow(new RuntimeException("should not interact with default auth manager"));
+ given(customAuthenticationManager.authenticate(any())).willReturn(Mono.just(new TestingAuthenticationToken("user", "password", "ROLE_USER", "ROLE_ADMIN")));
+
+ SecurityWebFilterChain securityWebFilter = this.http
+ .authenticationManager(defaultAuthenticationManager)
+ .formLogin()
+ .authenticationManager(customAuthenticationManager)
+ .and()
+ .build();
+
+ WebTestClient webTestClient = WebTestClientBuilder
+ .bindToWebFilters(securityWebFilter)
+ .build();
+
+ WebDriver driver = WebTestClientHtmlUnitDriverBuilder
+ .webTestClientSetup(webTestClient)
+ .build();
+
+ DefaultLoginPage loginPage = DefaultLoginPage.to(driver)
+ .assertAt();
+
+ HomePage homePage = loginPage.loginForm()
+ .username("user")
+ .password("password")
+ .submit(HomePage.class);
+
+ homePage.assertAt();
+
+ verifyZeroInteractions(defaultAuthenticationManager);
+ }
+
public static class CustomLoginPage {
private WebDriver driver;
diff --git a/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java
index a8dbc2ac264..8cf2b588b19 100644
--- a/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java
+++ b/config/src/test/java/org/springframework/security/config/web/server/LogoutSpecTests.java
@@ -21,6 +21,7 @@
import org.springframework.security.config.annotation.web.reactive.ServerHttpSecurityConfigurationBuilder;
import org.springframework.security.htmlunit.server.WebTestClientHtmlUnitDriverBuilder;
import org.springframework.security.web.server.SecurityWebFilterChain;
+import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
@@ -117,4 +118,45 @@ public void customLogout() {
.assertAt()
.assertLogout();
}
+
+ @Test
+ public void logoutWhenCustomSecurityContextRepositoryThenLogsOut() {
+ WebSessionServerSecurityContextRepository repository = new WebSessionServerSecurityContextRepository();
+ repository.setSpringSecurityContextAttrName("CUSTOM_CONTEXT_ATTR");
+ SecurityWebFilterChain securityWebFilter = this.http
+ .securityContextRepository(repository)
+ .authorizeExchange()
+ .anyExchange().authenticated()
+ .and()
+ .formLogin()
+ .and()
+ .logout()
+ .and()
+ .build();
+
+ WebTestClient webTestClient = WebTestClientBuilder
+ .bindToWebFilters(securityWebFilter)
+ .build();
+
+ WebDriver driver = WebTestClientHtmlUnitDriverBuilder
+ .webTestClientSetup(webTestClient)
+ .build();
+
+ FormLoginTests.DefaultLoginPage loginPage = FormLoginTests.HomePage.to(driver, FormLoginTests.DefaultLoginPage.class)
+ .assertAt();
+
+ FormLoginTests.HomePage homePage = loginPage.loginForm()
+ .username("user")
+ .password("password")
+ .submit(FormLoginTests.HomePage.class);
+
+ homePage.assertAt();
+
+ FormLoginTests.DefaultLogoutPage.to(driver)
+ .assertAt()
+ .logout();
+
+ FormLoginTests.HomePage.to(driver, FormLoginTests.DefaultLoginPage.class)
+ .assertAt();
+ }
}
diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java
index 9982ca608a0..1755d8e4279 100644
--- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java
+++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2ClientSpecTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,11 +34,17 @@
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
+import org.springframework.security.oauth2.client.web.server.ServerAuthorizationRequestRepository;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
+import org.springframework.security.oauth2.client.web.server.WebSessionOAuth2ServerAuthorizationRequestRepository;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
-import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
+import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
+import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests;
+import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses;
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.web.server.SecurityWebFilterChain;
@@ -69,8 +75,11 @@ public class OAuth2ClientSpecTests {
private ClientRegistration registration = TestClientRegistrations.clientRegistration().build();
+ private ApplicationContext context;
+
@Autowired
public void setApplicationContext(ApplicationContext context) {
+ this.context = context;
this.client = WebTestClient.bindToApplicationContext(context).build();
}
@@ -140,19 +149,40 @@ public void oauth2ClientWhenCustomObjectsThenUsed() {
ServerAuthenticationConverter converter = config.authenticationConverter;
ReactiveAuthenticationManager manager = config.manager;
+ ServerAuthorizationRequestRepository authorizationRequestRepository =
+ new WebSessionOAuth2ServerAuthorizationRequestRepository();
- OAuth2AuthorizationExchange exchange = TestOAuth2AuthorizationExchanges.success();
+ OAuth2AuthorizationRequest authorizationRequest = TestOAuth2AuthorizationRequests.request()
+ .redirectUri("/authorize/oauth2/code/registration-id")
+ .build();
+ OAuth2AuthorizationResponse authorizationResponse = TestOAuth2AuthorizationResponses.success()
+ .redirectUri("/authorize/oauth2/code/registration-id")
+ .build();
+ OAuth2AuthorizationExchange authorizationExchange =
+ new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse);
OAuth2AccessToken accessToken = TestOAuth2AccessTokens.noScopes();
- OAuth2AuthorizationCodeAuthenticationToken result = new OAuth2AuthorizationCodeAuthenticationToken(this.registration, exchange, accessToken);
+ OAuth2AuthorizationCodeAuthenticationToken result = new OAuth2AuthorizationCodeAuthenticationToken(
+ this.registration, authorizationExchange, accessToken);
when(converter.convert(any())).thenReturn(Mono.just(new TestingAuthenticationToken("a", "b", "c")));
when(manager.authenticate(any())).thenReturn(Mono.just(result));
- this.client.get()
- .uri("/authorize/oauth2/code/registration-id")
- .exchange()
- .expectStatus().is3xxRedirection();
+ WebTestClient client = WebTestClient.bindToApplicationContext(this.context)
+ .webFilter((exchange, chain) ->
+ authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, exchange)
+ .then(chain.filter(exchange).then(Mono.empty()))
+ )
+ .build();
+
+ client.get()
+ .uri(uriBuilder ->
+ uriBuilder.path("/authorize/oauth2/code/registration-id")
+ .queryParam(OAuth2ParameterNames.CODE, "code")
+ .queryParam(OAuth2ParameterNames.STATE, "state")
+ .build())
+ .exchange()
+ .expectStatus().is3xxRedirection();
verify(converter).convert(any());
verify(manager).authenticate(any());
diff --git a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java
index 16d0fb43d53..090fa7ac2e7 100644
--- a/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java
+++ b/config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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,21 +26,36 @@
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.htmlunit.server.WebTestClientHtmlUnitDriverBuilder;
+import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
+import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
+import org.springframework.security.oauth2.client.endpoint.ReactiveOAuth2AccessTokenResponseClient;
+import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeReactiveAuthenticationManager;
+import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
+import org.springframework.security.oauth2.client.userinfo.ReactiveOAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges;
+import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests;
+import org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationResponses;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.core.user.TestOAuth2Users;
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
@@ -48,12 +63,17 @@
import org.springframework.security.web.server.WebFilterChainProxy;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
+import org.springframework.web.server.WebHandler;
import reactor.core.publisher.Mono;
+import java.time.Duration;
+import java.time.Instant;
+
/**
* @author Rob Winch
* @since 5.1
@@ -63,6 +83,8 @@ public class OAuth2LoginTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
+ private WebTestClient client;
+
@Autowired
private WebFilterChainProxy springSecurity;
@@ -72,6 +94,20 @@ public class OAuth2LoginTests {
.clientSecret("secret")
.build();
+ private static ClientRegistration google = CommonOAuth2Provider.GOOGLE
+ .getBuilder("google")
+ .clientId("client")
+ .clientSecret("secret")
+ .build();
+
+ @Autowired
+ public void setApplicationContext(ApplicationContext context) {
+ if (context.getBeanNamesForType(WebHandler.class).length > 0) {
+ this.client = WebTestClient.bindToApplicationContext(context)
+ .build();
+ }
+ }
+
@Test
public void defaultLoginPageWithMultipleClientRegistrationsThenLinks() {
this.spring.register(OAuth2LoginWithMulitpleClientRegistrations.class).autowire();
@@ -97,11 +133,6 @@ public void defaultLoginPageWithMultipleClientRegistrationsThenLinks() {
static class OAuth2LoginWithMulitpleClientRegistrations {
@Bean
InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() {
- ClientRegistration google = CommonOAuth2Provider.GOOGLE
- .getBuilder("google")
- .clientId("client")
- .clientSecret("secret")
- .build();
return new InMemoryReactiveClientRegistrationRepository(github, google);
}
}
@@ -123,6 +154,22 @@ public void defaultLoginPageWithSingleClientRegistrationThenRedirect() {
assertThat(driver.getCurrentUrl()).startsWith("https://github.com/login/oauth/authorize");
}
+ // gh-8118
+ @Test
+ public void defaultLoginPageWithSingleClientRegistrationAndXhrRequestThenDoesNotRedirectForAuthorization() {
+ this.spring.register(OAuth2LoginWithSingleClientRegistrations.class, WebFluxConfig.class).autowire();
+
+ this.client.get()
+ .uri("/")
+ .header("X-Requested-With", "XMLHttpRequest")
+ .exchange()
+ .expectStatus().is3xxRedirection()
+ .expectHeader().valueEquals(HttpHeaders.LOCATION, "/login");
+ }
+
+ @EnableWebFlux
+ static class WebFluxConfig { }
+
@EnableWebFluxSecurity
static class OAuth2LoginWithSingleClientRegistrations {
@Bean
@@ -182,6 +229,78 @@ public SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
}
}
+ // gh-5562
+ @Test
+ public void oauth2LoginWhenAccessTokenRequestFailsThenDefaultRedirectToLogin() {
+ this.spring.register(OAuth2LoginWithMulitpleClientRegistrations.class,
+ OAuth2LoginWithCustomBeansConfig.class).autowire();
+
+ WebTestClient webTestClient = WebTestClientBuilder
+ .bindToWebFilters(this.springSecurity)
+ .build();
+
+ OAuth2AuthorizationRequest request = TestOAuth2AuthorizationRequests.request().scope("openid").build();
+ OAuth2AuthorizationResponse response = TestOAuth2AuthorizationResponses.success().build();
+ OAuth2AuthorizationExchange exchange = new OAuth2AuthorizationExchange(request, response);
+ OAuth2AccessToken accessToken = new OAuth2AccessToken(
+ OAuth2AccessToken.TokenType.BEARER, "openid", Instant.now(), Instant.now().plus(Duration.ofDays(1)));
+ OAuth2AuthorizationCodeAuthenticationToken authenticationToken =
+ new OAuth2AuthorizationCodeAuthenticationToken(google, exchange, accessToken);
+
+ OAuth2LoginWithCustomBeansConfig config = this.spring.getContext().getBean(OAuth2LoginWithCustomBeansConfig.class);
+
+ ServerAuthenticationConverter converter = config.authenticationConverter;
+ when(converter.convert(any())).thenReturn(Mono.just(authenticationToken));
+
+ ReactiveOAuth2AccessTokenResponseClient tokenResponseClient = config.tokenResponseClient;
+ OAuth2Error oauth2Error = new OAuth2Error("invalid_request", "Invalid request", null);
+ when(tokenResponseClient.getTokenResponse(any())).thenThrow(new OAuth2AuthenticationException(oauth2Error));
+
+ webTestClient.get()
+ .uri("/login/oauth2/code/google")
+ .exchange()
+ .expectStatus()
+ .is3xxRedirection()
+ .expectHeader()
+ .valueEquals("Location", "/login?error");
+ }
+
+ @Configuration
+ static class OAuth2LoginWithCustomBeansConfig {
+
+ ServerAuthenticationConverter authenticationConverter = mock(ServerAuthenticationConverter.class);
+
+ ReactiveOAuth2AccessTokenResponseClient tokenResponseClient =
+ mock(ReactiveOAuth2AccessTokenResponseClient.class);
+
+ ReactiveOAuth2UserService userService = mock(ReactiveOAuth2UserService.class);
+
+ @Bean
+ public SecurityWebFilterChain springSecurityFilter(ServerHttpSecurity http) {
+ // @formatter:off
+ http
+ .authorizeExchange()
+ .anyExchange().authenticated()
+ .and()
+ .oauth2Login()
+ .authenticationConverter(authenticationConverter)
+ .authenticationManager(authenticationManager());
+ return http.build();
+ // @formatter:on
+ }
+
+ private ReactiveAuthenticationManager authenticationManager() {
+ OidcAuthorizationCodeReactiveAuthenticationManager oidc =
+ new OidcAuthorizationCodeReactiveAuthenticationManager(tokenResponseClient, userService);
+ return oidc;
+ }
+
+ @Bean
+ public ReactiveOAuth2AccessTokenResponseClient accessTokenResponseClient() {
+ return tokenResponseClient;
+ }
+ }
+
static class GitHubWebFilter implements WebFilter {
@Override
diff --git a/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java b/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java
index 58516f14baa..ff538356b29 100644
--- a/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java
+++ b/config/src/test/java/org/springframework/security/config/web/server/ServerHttpSecurityTests.java
@@ -19,6 +19,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.Arrays;
@@ -190,6 +192,25 @@ public void csrfServerLogoutHandlerAppliedIfCsrfIsEnabled() {
.isEqualTo(Arrays.asList(SecurityContextServerLogoutHandler.class, CsrfServerLogoutHandler.class));
}
+ @Test
+ public void basicWithCustomAuthenticationManager() {
+ ReactiveAuthenticationManager customAuthenticationManager = mock(ReactiveAuthenticationManager.class);
+ given(customAuthenticationManager.authenticate(any())).willReturn(Mono.just(new TestingAuthenticationToken("rob", "rob", "ROLE_USER", "ROLE_ADMIN")));
+
+ SecurityWebFilterChain securityFilterChain = this.http.httpBasic().authenticationManager(customAuthenticationManager).and().build();
+ WebFilterChainProxy springSecurityFilterChain = new WebFilterChainProxy(securityFilterChain);
+ WebTestClient client = WebTestClientBuilder.bindToWebFilters(springSecurityFilterChain).build();
+
+ client.get()
+ .uri("/")
+ .headers(headers -> headers.setBasicAuth("rob", "rob"))
+ .exchange()
+ .expectStatus().isOk()
+ .expectBody(String.class).consumeWith(b -> assertThat(b.getResponseBody()).isEqualTo("ok"));
+
+ verifyZeroInteractions(this.authenticationManager);
+ }
+
private Optional getWebFilter(SecurityWebFilterChain filterChain, Class filterClass) {
return (Optional) filterChain.getWebFilters()
.filter(Objects::nonNull)
diff --git a/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java b/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java
index 563f726a42f..97b201d0855 100644
--- a/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java
+++ b/core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java
@@ -17,7 +17,6 @@
import java.io.Serializable;
import java.util.Collection;
-import java.util.HashSet;
import java.util.Set;
import org.springframework.security.access.PermissionEvaluator;
@@ -158,7 +157,6 @@ public void setDefaultRolePrefix(String defaultRolePrefix) {
private Set getAuthoritySet() {
if (roles == null) {
- roles = new HashSet<>();
Collection extends GrantedAuthority> userAuthorities = authentication
.getAuthorities();
diff --git a/core/src/main/java/org/springframework/security/authentication/jaas/JaasAuthenticationProvider.java b/core/src/main/java/org/springframework/security/authentication/jaas/JaasAuthenticationProvider.java
index 2b38352461e..34a3f231eef 100644
--- a/core/src/main/java/org/springframework/security/authentication/jaas/JaasAuthenticationProvider.java
+++ b/core/src/main/java/org/springframework/security/authentication/jaas/JaasAuthenticationProvider.java
@@ -129,7 +129,7 @@
* </property>
*
*
- * A configuration note: The JaasAuthenticationProvider uses the security properites
+ * A configuration note: The JaasAuthenticationProvider uses the security properties
* "login.config.url.X" to configure jaas. If you would like to customize the way Jaas
* gets configured, create a subclass of this and override the
* {@link #configureJaas(Resource)} method.
diff --git a/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java b/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java
index b476ece2c86..b34f942e1c4 100644
--- a/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java
+++ b/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java
@@ -132,13 +132,18 @@ public void registerNewSession(String sessionId, Object principal) {
sessionIds.put(sessionId,
new SessionInformation(principal, sessionId, new Date()));
- Set sessionsUsedByPrincipal = principals.computeIfAbsent(principal, key -> new CopyOnWriteArraySet<>());
- sessionsUsedByPrincipal.add(sessionId);
+ principals.compute(principal, (key, sessionsUsedByPrincipal) -> {
+ if (sessionsUsedByPrincipal == null) {
+ sessionsUsedByPrincipal = new CopyOnWriteArraySet<>();
+ }
+ sessionsUsedByPrincipal.add(sessionId);
- if (logger.isTraceEnabled()) {
- logger.trace("Sessions used by '" + principal + "' : "
- + sessionsUsedByPrincipal);
- }
+ if (logger.isTraceEnabled()) {
+ logger.trace("Sessions used by '" + principal + "' : "
+ + sessionsUsedByPrincipal);
+ }
+ return sessionsUsedByPrincipal;
+ });
}
public void removeSessionInformation(String sessionId) {
@@ -157,32 +162,29 @@ public void removeSessionInformation(String sessionId) {
sessionIds.remove(sessionId);
- Set sessionsUsedByPrincipal = principals.get(info.getPrincipal());
-
- if (sessionsUsedByPrincipal == null) {
- return;
- }
-
- if (logger.isDebugEnabled()) {
- logger.debug("Removing session " + sessionId
- + " from principal's set of registered sessions");
- }
+ principals.computeIfPresent(info.getPrincipal(), (key, sessionsUsedByPrincipal) -> {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Removing session " + sessionId
+ + " from principal's set of registered sessions");
+ }
- sessionsUsedByPrincipal.remove(sessionId);
+ sessionsUsedByPrincipal.remove(sessionId);
- if (sessionsUsedByPrincipal.isEmpty()) {
- // No need to keep object in principals Map anymore
- if (logger.isDebugEnabled()) {
- logger.debug("Removing principal " + info.getPrincipal()
- + " from registry");
+ if (sessionsUsedByPrincipal.isEmpty()) {
+ // No need to keep object in principals Map anymore
+ if (logger.isDebugEnabled()) {
+ logger.debug("Removing principal " + info.getPrincipal()
+ + " from registry");
+ }
+ sessionsUsedByPrincipal = null;
}
- principals.remove(info.getPrincipal());
- }
- if (logger.isTraceEnabled()) {
- logger.trace("Sessions used by '" + info.getPrincipal() + "' : "
- + sessionsUsedByPrincipal);
- }
+ if (logger.isTraceEnabled()) {
+ logger.trace("Sessions used by '" + info.getPrincipal() + "' : "
+ + sessionsUsedByPrincipal);
+ }
+ return sessionsUsedByPrincipal;
+ });
}
}
diff --git a/core/src/main/resources/org/springframework/security/messages.properties b/core/src/main/resources/org/springframework/security/messages.properties
index 665a742002e..a84f259753f 100644
--- a/core/src/main/resources/org/springframework/security/messages.properties
+++ b/core/src/main/resources/org/springframework/security/messages.properties
@@ -31,6 +31,7 @@ DigestAuthenticationFilter.usernameNotFound=Username {0} not found
JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority
JdbcDaoImpl.notFound=User {0} not found
LdapAuthenticationProvider.badCredentials=Bad credentials
+LdapAuthenticationProvider.badLdapConnection=Connection to LDAP server failed
LdapAuthenticationProvider.credentialsExpired=User credentials have expired
LdapAuthenticationProvider.disabled=User is disabled
LdapAuthenticationProvider.expired=User account has expired
diff --git a/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java
index e0b80e5dd04..c1ad734aeba 100644
--- a/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java
+++ b/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java
@@ -65,6 +65,10 @@ public BCryptPasswordEncoder(int strength, SecureRandom random) {
}
public String encode(CharSequence rawPassword) {
+ if (rawPassword == null) {
+ throw new IllegalArgumentException("rawPassword cannot be null");
+ }
+
String salt;
if (strength > 0) {
if (random != null) {
@@ -81,6 +85,10 @@ public String encode(CharSequence rawPassword) {
}
public boolean matches(CharSequence rawPassword, String encodedPassword) {
+ if (rawPassword == null) {
+ throw new IllegalArgumentException("rawPassword cannot be null");
+ }
+
if (encodedPassword == null || encodedPassword.length() == 0) {
logger.warn("Empty encoded password");
return false;
diff --git a/crypto/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java b/crypto/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java
index 7e0c5e8295e..7ebfb5a356d 100644
--- a/crypto/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java
+++ b/crypto/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2016 the original author or authors.
+ * Copyright 2011-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,16 +32,13 @@ public class Encryptors {
* (Password-Based Key Derivation Function #2). Salts the password to prevent
* dictionary attacks against the key. The provided salt is expected to be
* hex-encoded; it should be random and at least 8 bytes in length. Also applies a
- * random 16 byte initialization vector to ensure each encrypted message will be
+ * random 16-byte initialization vector to ensure each encrypted message will be
* unique. Requires Java 6.
*
* @param password the password used to generate the encryptor's secret key; should
* not be shared
* @param salt a hex-encoded, random, site-global salt value to use to generate the
* key
- *
- * @see #standard(CharSequence, CharSequence) which uses the slightly weaker CBC mode
- * (instead of GCM)
*/
public static BytesEncryptor stronger(CharSequence password, CharSequence salt) {
return new AesBytesEncryptor(password.toString(), salt,
@@ -53,13 +50,21 @@ public static BytesEncryptor stronger(CharSequence password, CharSequence salt)
* Derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation
* Function #2). Salts the password to prevent dictionary attacks against the key. The
* provided salt is expected to be hex-encoded; it should be random and at least 8
- * bytes in length. Also applies a random 16 byte initialization vector to ensure each
+ * bytes in length. Also applies a random 16-byte initialization vector to ensure each
* encrypted message will be unique. Requires Java 6.
+ * NOTE: This mode is not
+ * authenticated
+ * and does not provide any guarantees about the authenticity of the data.
+ * For a more secure alternative, users should prefer
+ * {@link #stronger(CharSequence, CharSequence)}.
*
* @param password the password used to generate the encryptor's secret key; should
* not be shared
* @param salt a hex-encoded, random, site-global salt value to use to generate the
* key
+ *
+ * @see #stronger(CharSequence, CharSequence), which uses the significatly more secure
+ * GCM (instead of CBC)
*/
public static BytesEncryptor standard(CharSequence password, CharSequence salt) {
return new AesBytesEncryptor(password.toString(), salt,
@@ -100,7 +105,10 @@ public static TextEncryptor text(CharSequence password, CharSequence salt) {
* not be shared
* @param salt a hex-encoded, random, site-global salt value to use to generate the
* secret key
+ * @deprecated This encryptor is not secure. Instead, look to your data store for a
+ * mechanism to query encrypted data.
*/
+ @Deprecated
public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(),
salt));
diff --git a/crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java
index a0110e86124..7fe06a979de 100644
--- a/crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java
+++ b/crypto/src/main/java/org/springframework/security/crypto/password/Md4PasswordEncoder.java
@@ -83,8 +83,6 @@ public class Md4PasswordEncoder implements PasswordEncoder {
private StringKeyGenerator saltGenerator = new Base64StringKeyGenerator();
private boolean encodeHashAsBase64;
- private Digester digester;
-
public void setEncodeHashAsBase64(boolean encodeHashAsBase64) {
this.encodeHashAsBase64 = encodeHashAsBase64;
diff --git a/crypto/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java b/crypto/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java
index 907eb7c718e..3c28e167419 100644
--- a/crypto/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java
+++ b/crypto/src/main/java/org/springframework/security/crypto/password/NoOpPasswordEncoder.java
@@ -26,7 +26,8 @@
* @deprecated This PasswordEncoder is not secure. Instead use an
* adaptive one way function like BCryptPasswordEncoder, Pbkdf2PasswordEncoder, or
* SCryptPasswordEncoder. Even better use {@link DelegatingPasswordEncoder} which supports
- * password upgrades.
+ * password upgrades. There are no plans to remove this support. It is deprecated to indicate that
+ * this is a legacy implementation and using it is considered insecure.
*/
@Deprecated
public final class NoOpPasswordEncoder implements PasswordEncoder {
diff --git a/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java b/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java
index d637c085f44..ec34e95c5b5 100644
--- a/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java
+++ b/crypto/src/test/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoderTests.java
@@ -92,4 +92,15 @@ public void doesntMatchBogusEncodedValue() {
assertThat(encoder.matches("password", "012345678901234567890123456789")).isFalse();
}
+ @Test(expected = IllegalArgumentException.class)
+ public void encodeNullRawPassword() {
+ BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+ encoder.encode(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void matchNullRawPassword() {
+ BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+ encoder.matches(null, "does-not-matter");
+ }
}
diff --git a/dep-updates.txt b/dep-updates.txt
new file mode 100644
index 00000000000..9da3481c8cf
--- /dev/null
+++ b/dep-updates.txt
@@ -0,0 +1,2873 @@
+
+------------------------------------------------------------
+:spring-security-config Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - ldapsdk:ldapsdk:4.1
+ - org.eclipse.persistence:javax.persistence:2.2.1
+ - org.openid4java:openid4java-nodeps:0.9.6
+ - org.springframework.ldap:spring-ldap-core:2.3.2.RELEASE
+
+The following dependencies have later release versions:
+ - cglib:cglib-nodep [3.2.10 -> 3.2.12]
+ https://github.com/cglib/cglib
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - com.squareup.okhttp3:mockwebserver [3.12.2 -> 4.0.1]
+ https://github.com/square/okhttp
+ - io.projectreactor:reactor-core [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor.netty:reactor-netty [0.8.6.RELEASE -> 0.9.0.M3]
+ https://github.com/reactor/reactor-netty
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.annotation:jsr250-api [1.0 -> 1.0-20050927.133100]
+ https://jax-ws.dev.java.net/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - net.sourceforge.htmlunit:htmlunit [2.33 -> 2.35.0]
+ http://htmlunit.sourceforge.net
+ - org.apache.directory.server:apacheds-core [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-core-entry [1.5.5 -> 1.5.7]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-protocol-ldap [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-protocol-shared [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-server-jndi [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.shared:shared-ldap [0.9.15 -> 1.0.0-M1]
+ http://directory.apache.org/
+ - org.aspectj:aspectjweaver [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.codehaus.groovy:groovy-all [2.4.14 -> 3.0.0-beta-2]
+ https://groovy-lang.org
+ - org.hibernate:hibernate-entitymanager [5.3.9.Final -> 5.4.4.Final]
+ http://hibernate.org/orm
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.powermock:powermock-api-mockito2 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-api-support [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-core [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4-common [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-reflect [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-java [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.spockframework:spock-core [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.spockframework:spock-spring [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-expression [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-orm [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webflux [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-websocket [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.data:spring-data-jpa [2.1.6.RELEASE -> 2.2.0.RC2]
+ https://projects.spring.io/spring-data-jpa
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-taglibs Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.codehaus.groovy:groovy-all [2.4.14 -> 3.0.0-beta-2]
+ https://groovy-lang.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.spockframework:spock-core [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.spockframework:spock-spring [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-expression [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-cas Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+ - net.sf.ehcache:ehcache:2.10.6
+ - org.jasig.cas.client:cas-client-core:3.5.1
+ - org.skyscreamer:jsonassert:1.5.0
+
+The following dependencies have later release versions:
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-crypto Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.bouncycastle:bcpkix-jdk15on [1.61 -> 1.62]
+ http://www.bouncycastle.org/java.html
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-jcl [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-oauth2-jose Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - com.nimbusds:nimbus-jose-jwt [6.0.2 -> 7.7]
+ https://bitbucket.org/connect2id/nimbus-jose-jwt
+ - com.squareup.okhttp3:mockwebserver [3.12.2 -> 4.0.1]
+ https://github.com/square/okhttp
+ - io.projectreactor:reactor-core [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor.netty:reactor-netty [0.8.6.RELEASE -> 0.9.0.M3]
+ https://github.com/reactor/reactor-netty
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.powermock:powermock-api-mockito2 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-api-support [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-core [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4-common [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-reflect [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webflux [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-oauth2-resource-server Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+
+The following dependencies have later release versions:
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - com.squareup.okhttp3:mockwebserver [3.12.2 -> 4.0.1]
+ https://github.com/square/okhttp
+ - io.projectreactor:reactor-core [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor:reactor-test [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor.netty:reactor-netty [0.8.6.RELEASE -> 0.9.0.M3]
+ https://github.com/reactor/reactor-netty
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webflux [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-oauth2-core Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - com.nimbusds:oauth2-oidc-sdk [6.0 -> 6.14]
+ https://bitbucket.org/connect2id/oauth-2.0-sdk-with-openid-connect-extensions
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.powermock:powermock-api-mockito2 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-api-support [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-core [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4-common [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-reflect [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webflux [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-oauth2-client Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+
+The following dependencies have later release versions:
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - com.nimbusds:oauth2-oidc-sdk [6.0 -> 6.14]
+ https://bitbucket.org/connect2id/oauth-2.0-sdk-with-openid-connect-extensions
+ - com.squareup.okhttp3:mockwebserver [3.12.2 -> 4.0.1]
+ https://github.com/square/okhttp
+ - io.projectreactor:reactor-core [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor:reactor-test [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor.netty:reactor-netty [0.8.6.RELEASE -> 0.9.0.M3]
+ https://github.com/reactor/reactor-netty
+ - io.projectreactor.tools:blockhound [1.0.0.M4 -> 1.0.0.M5]
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.powermock:powermock-api-mockito2 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-api-support [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-core [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4-common [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-reflect [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webflux [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-test Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.skyscreamer:jsonassert:1.5.0
+
+The following dependencies have later release versions:
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - io.projectreactor:reactor-core [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor:reactor-test [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.powermock:powermock-api-mockito2 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-api-support [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-core [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4-common [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-reflect [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webflux [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-remoting Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-openid Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+ - net.sourceforge.nekohtml:nekohtml:1.9.22
+ - org.openid4java:openid4java-nodeps:0.9.6
+
+The following dependencies have later release versions:
+ - com.google.inject:guice [3.0 -> 4.2.2]
+ https://github.com/google/guice
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.apache.httpcomponents:httpclient [4.5.7 -> 4.5.9]
+ http://hc.apache.org/httpcomponents-client
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-web Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.skyscreamer:jsonassert:1.5.0
+
+The following dependencies have later release versions:
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - commons-codec:commons-codec [1.11 -> 1.13]
+ https://commons.apache.org/proper/commons-codec/
+ - io.projectreactor:reactor-core [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor:reactor-test [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.codehaus.groovy:groovy-all [2.4.14 -> 3.0.0-beta-2]
+ https://groovy-lang.org
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.powermock:powermock-api-mockito2 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-api-support [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-core [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4-common [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-reflect [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.spockframework:spock-core [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.spockframework:spock-spring [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-expression [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webflux [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-data Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.data:spring-data-commons [2.1.6.RELEASE -> 2.2.0.RC2]
+ https://www.spring.io/spring-data
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-core Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - net.sf.ehcache:ehcache:2.10.6
+ - org.skyscreamer:jsonassert:1.5.0
+
+The following dependencies have later release versions:
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - commons-collections:commons-collections [3.2.2 -> 20040616]
+ - io.projectreactor:reactor-core [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.projectreactor:reactor-test [3.2.8.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.annotation:jsr250-api [1.0 -> 1.0-20050927.133100]
+ https://jax-ws.dev.java.net/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.aspectj:aspectjrt [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.powermock:powermock-api-mockito2 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-api-support [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-core [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4-common [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-reflect [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-expression [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-messaging Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - commons-codec:commons-codec [1.11 -> 1.13]
+ https://commons.apache.org/proper/commons-codec/
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.powermock:powermock-api-mockito2 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-api-support [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-core [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4 [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-module-junit4-common [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.powermock:powermock-reflect [2.0.0 -> 2.0.2]
+ http://www.powermock.org
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.spockframework:spock-core [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.spockframework:spock-spring [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-expression [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-messaging [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-websocket [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-acl Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - net.sf.ehcache:ehcache:2.10.6
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context-support [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-ldap Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - ldapsdk:ldapsdk:4.1
+ - org.springframework.ldap:spring-ldap-core:2.3.2.RELEASE
+
+The following dependencies have later release versions:
+ - com.unboundid:unboundid-ldapsdk [4.0.10 -> 4.0.11]
+ https://github.com/pingidentity/ldapsdk
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.apache.directory.server:apacheds-core [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-core-entry [1.5.5 -> 1.5.7]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-protocol-ldap [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-protocol-shared [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-server-jndi [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.shared:shared-ldap [0.9.15 -> 1.0.0-M1]
+ http://directory.apache.org/
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-itest-context Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.aspectj:aspectjweaver [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.python:jython [2.5.0 -> 2.7.1b3]
+ http://www.jython.org/
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-itest-web Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet:javax.servlet-api:4.0.1
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-inmemory Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-hellojs Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - com.fasterxml.jackson.core:jackson-databind [2.9.8 -> 2.10.0.pr1]
+ http://github.com/FasterXML/jackson
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-helloworld Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-openid Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - net.sourceforge.nekohtml:nekohtml:1.9.22
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-preauth Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-hellomvc Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-concurrency Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-form Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - com.sun.xml.bind:jaxb-core:2.3.0.1
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - com.sun.xml.bind:jaxb-impl [2.3.0.1 -> 2.4.0-b180830.0438]
+ http://jaxb.java.net
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-data Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.validation:validation-api:2.0.1.Final
+ - org.eclipse.persistence:javax.persistence:2.2.1
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-entitymanager [5.3.9.Final -> 5.4.4.Final]
+ http://hibernate.org/orm
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.data:spring-data-jpa [2.1.6.RELEASE -> 2.2.0.RC2]
+ https://projects.spring.io/spring-data-jpa
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-aspectj Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.aspectj:aspectjrt [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.aspectj:aspectjtools [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-jdbc Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - com.sun.xml.bind:jaxb-core:2.3.0.1
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - com.sun.xml.bind:jaxb-impl [2.3.0.1 -> 2.4.0-b180830.0438]
+ http://jaxb.java.net
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-x509 Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:jul-to-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-ldap Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.apache.directory.server:apacheds-core [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-core-entry [1.5.5 -> 1.5.7]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-protocol-ldap [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-protocol-shared [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-server-jndi [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.shared:shared-ldap [0.9.15 -> 1.0.0-M1]
+ http://directory.apache.org/
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-rememberme Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-javaconfig-messages Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.validation:validation-api:2.0.1.Final
+ - org.eclipse.persistence:javax.persistence:2.2.1
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+ - org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect [2.3.0 -> 2.4.1]
+ https://github.com/ultraq/thymeleaf-layout-dialect/
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-entitymanager [5.3.9.Final -> 5.4.4.Final]
+ http://hibernate.org/orm
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-aspects [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-instrument [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-orm [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.data:spring-data-jpa [2.1.6.RELEASE -> 2.2.0.RC2]
+ https://projects.spring.io/spring-data-jpa
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-oauth2webclient-webflux Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
+
+The following dependencies have later release versions:
+ - io.projectreactor.netty:reactor-netty [0.8.5.RELEASE -> 0.9.0.M3]
+ https://github.com/reactor/reactor-netty
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-thymeleaf [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-thymeleaf
+ - org.springframework.boot:spring-boot-starter-webflux [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-webflux
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-hellowebflux-method Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - io.projectreactor:reactor-test [3.2.6.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-webflux [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-webflux
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-webflux-form Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.skyscreamer:jsonassert:1.5.0
+ - org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
+
+The following dependencies have later release versions:
+ - io.projectreactor:reactor-test [3.2.6.RELEASE -> 3.3.0.M3]
+ https://github.com/reactor/reactor-core
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-thymeleaf [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-thymeleaf
+ - org.springframework.boot:spring-boot-starter-webflux [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-webflux
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-oauth2resourceserver-webflux Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - com.squareup.okhttp3:mockwebserver [3.12.2 -> 4.0.1]
+ https://github.com/square/okhttp
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-webflux [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-webflux
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-oauth2authorizationserver Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - com.sun.xml.bind:jaxb-core:2.3.0.1
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+
+The following dependencies have later release versions:
+ - com.nimbusds:nimbus-jose-jwt [6.0.2 -> 7.7]
+ https://bitbucket.org/connect2id/nimbus-jose-jwt
+ - com.sun.xml.bind:jaxb-impl [2.3.0.1 -> 2.4.0-b180830.0438]
+ http://jaxb.java.net
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-security [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-security
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-web [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web
+ - org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure [2.1.3.RELEASE -> 2.2.0.M4]
+ https://spring.io/spring-security
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-helloworld Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-thymeleaf [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-thymeleaf
+ - org.springframework.boot:spring-boot-starter-web [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-hellowebfluxfn Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-webflux [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-webflux
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-insecure Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-thymeleaf [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-thymeleaf
+ - org.springframework.boot:spring-boot-starter-web [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-oauth2webclient Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
+
+The following dependencies have later release versions:
+ - io.projectreactor.netty:reactor-netty [0.8.5.RELEASE -> 0.9.0.M3]
+ https://github.com/reactor/reactor-netty
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webflux [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-thymeleaf [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-thymeleaf
+ - org.springframework.boot:spring-boot-starter-web [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-oauth2resourceserver Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - com.squareup.okhttp3:mockwebserver [3.12.2 -> 4.0.1]
+ https://github.com/square/okhttp
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-web [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-oauth2login-webflux Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - net.sourceforge.htmlunit:htmlunit [2.33 -> 2.35.0]
+ http://htmlunit.sourceforge.net
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-thymeleaf [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-thymeleaf
+ - org.springframework.boot:spring-boot-starter-webflux [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-webflux
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-oauth2login Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.0.4.RELEASE
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - net.sourceforge.htmlunit:htmlunit [2.33 -> 2.35.0]
+ http://htmlunit.sourceforge.net
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-thymeleaf [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-thymeleaf
+ - org.springframework.boot:spring-boot-starter-web [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-boot-hellowebflux Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.5.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework.boot:spring-boot-starter-test [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test
+ - org.springframework.boot:spring-boot-starter-webflux [2.1.3.RELEASE -> 2.2.0.M4]
+ https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-webflux
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-cassample Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - commons-httpclient:commons-httpclient:3.1
+ - net.sf.ehcache:ehcache:2.10.6
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.jasig.cas.client:cas-client-core:3.5.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.codehaus.groovy:groovy [2.4.14 -> 3.0.0-beta-2]
+ https://groovy-lang.org
+ - org.codehaus.groovy:groovy-all [2.4.14 -> 3.0.0-beta-2]
+ https://groovy-lang.org
+ - org.eclipse.jetty:jetty-server [9.4.12.v20180830 -> 10.0.0-alpha0]
+ http://www.eclipse.org/jetty
+ - org.eclipse.jetty:jetty-servlet [9.4.12.v20180830 -> 10.0.0-alpha0]
+ http://www.eclipse.org/jetty
+ - org.gebish:geb-spock [0.10.0 -> 3.0.1]
+ http://www.gebish.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.spockframework:spock-core [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.spockframework:spock-spring [1.0-groovy-2.4 -> 1.3-RC1-groovy-2.5]
+ http://spockframework.org
+ - org.springframework:spring-context-support [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-casserver Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.aspectj:aspectjrt [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.aspectj:aspectjtools [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.aspectj:aspectjweaver [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.jasig.cas:cas-server-webapp [4.0.0 -> 4.2.7]
+ http://www.apereo.org/cas
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-cas Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-tutorial Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-helloworld Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.skyscreamer:jsonassert:1.5.0
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-openid Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-preauth Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-insecuremvc Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - opensymphony:sitemesh [2.4.2 -> 2.5-atlassian-11]
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-insecure Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.xml.bind:jaxb-api:2.4.0-b180830.0359
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-gae Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - javax.validation:validation-api:2.0.1.Final
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - com.google.appengine:appengine [1.9.71 -> 1.9.76]
+ http://code.google.com/appengine/
+ - com.google.appengine:appengine-api-1.0-sdk [1.9.71 -> 1.9.76]
+ http://code.google.com/appengine/
+ - com.google.appengine:appengine-api-labs [1.9.71 -> 1.9.76]
+ http://code.google.com/appengine/
+ - com.google.appengine:appengine-api-stubs [1.9.71 -> 1.9.76]
+ http://code.google.com/appengine/
+ - com.google.appengine:appengine-testing [1.9.71 -> 1.9.76]
+ http://code.google.com/appengine/
+ - com.google.cloud.tools:appengine-gradle-plugin [1.3.5 -> 2.1.0]
+ https://github.com/GoogleCloudPlatform/app-gradle-plugin
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hibernate:hibernate-validator [6.0.16.Final -> 6.1.0.Alpha6]
+ http://hibernate.org/validator
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context-support [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-aspectj Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.aspectj:aspectjrt [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.aspectj:aspectjtools [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-dms Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - net.sf.ehcache:ehcache:2.10.6
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context-support [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-ldap Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.apache.directory.server:apacheds-core [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-core-entry [1.5.5 -> 1.5.7]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-protocol-ldap [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-protocol-shared [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.server:apacheds-server-jndi [1.5.5 -> 2.0.0-M24]
+ http://directory.apache.org/apacheds/1.5
+ - org.apache.directory.shared:shared-ldap [0.9.15 -> 1.0.0-M1]
+ http://directory.apache.org/
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-jaas Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-contacts Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - net.sf.ehcache:ehcache:2.10.6
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.hsqldb:hsqldb [2.4.1 -> 2.5.0]
+ http://hsqldb.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.seleniumhq.selenium:htmlunit-driver [2.33.3 -> 2.35.1]
+ https://github.com/SeleniumHQ/htmlunit-driver
+ - org.seleniumhq.selenium:selenium-support [3.141.59 -> 4.0.0-alpha-2]
+ http://www.seleniumhq.org/
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context-support [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-jdbc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-tx [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-samples-xml-servletapi Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies are using the latest release version:
+ - javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.2
+ - org.apache.taglibs:taglibs-standard-jstlel:1.2.5
+ - org.gretty:gretty-runner-jetty7:2.3.1
+ - org.gretty:gretty-runner-jetty8:2.3.1
+ - org.gretty:gretty-runner-jetty9:2.3.1
+ - org.gretty:gretty-runner-jetty93:2.3.1
+ - org.gretty:gretty-runner-jetty94:2.3.1
+ - org.gretty:gretty-runner-tomcat7:2.3.1
+ - org.gretty:gretty-runner-tomcat8:2.3.1
+ - org.gretty:gretty-runner-tomcat85:2.3.1
+ - org.gretty:gretty-runner-tomcat9:2.3.1
+ - org.gretty:gretty-starter:2.3.1
+ - org.springframework:springloaded:1.2.8.RELEASE
+
+The following dependencies have later release versions:
+ - ch.qos.logback:logback-classic [1.2.3 -> 1.3.0-alpha4]
+ http://logback.qos.ch
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - javax.servlet:javax.servlet-api [3.1.0 -> 4.0.1]
+ https://javaee.github.io/servlet-spec/
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.slf4j:jcl-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:log4j-over-slf4j [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.slf4j:slf4j-api [1.7.26 -> 2.0.0-alpha0]
+ http://www.slf4j.org
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context-support [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-web [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-webmvc [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
+
+------------------------------------------------------------
+:spring-security-aspects Project Dependency Updates (report to plain text file)
+------------------------------------------------------------
+
+The following dependencies have later release versions:
+ - io.spring.javaformat:spring-javaformat-checkstyle [0.0.7 -> 0.0.15]
+ https://github.com/spring-io/spring-javaformat/#/spring-javaformat/spring-javaformat-checkstyle
+ - junit:junit [4.12 -> 4.13-beta-3]
+ http://junit.org
+ - org.aspectj:aspectjrt [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.aspectj:aspectjtools [1.9.2 -> 1.9.4]
+ http://www.aspectj.org
+ - org.assertj:assertj-core [3.11.1 -> 3.13.2]
+ http://assertj.org
+ - org.mockito:mockito-core [2.23.4 -> 3.0.0]
+ https://github.com/mockito/mockito
+ - org.springframework:spring-aop [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-beans [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-context [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-core [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+ - org.springframework:spring-test [5.1.6.RELEASE -> 5.2.0.RC1]
+ https://github.com/spring-projects/spring-framework
+
+Gradle release-candidate updates:
+ - Gradle: [4.10.2 -> 5.5.1 -> 5.6-rc-1]
diff --git a/docs/manual/src/docs/asciidoc/_includes/preface/whats-new.adoc b/docs/manual/src/docs/asciidoc/_includes/preface/whats-new.adoc
index 0508f8adeea..c3c2c353b53 100644
--- a/docs/manual/src/docs/asciidoc/_includes/preface/whats-new.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/preface/whats-new.adoc
@@ -17,7 +17,7 @@ Below are the highlights of the release.
* <> support for selecting an `AccessDeniedHandler` by `RequestMatcher`
* <> support for excluding certain requests
* Added Support for <>
-* Added {security-api-url}core/src/main/java/org/springframework/security/core/Transient.java[@Transient] authentication tokens
+* Added {security-api-url}org/springframework/security/core/Transient.html[@Transient] authentication tokens
* A modern look-and-feel for the default log in page
=== WebFlux
diff --git a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc
index 56a6d88ad3f..648fe7e3662 100644
--- a/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc
@@ -341,7 +341,7 @@ Resource Server uses `JwtTimestampValidator` to verify a token's validity window
@Bean
ReactiveJwtDecoder jwtDecoder() {
NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
- ReactiveJwtDecoders.withOidcIssuerLocation(issuerUri);
+ ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
OAuth2TokenValidator withClockSkew = new DelegatingOAuth2TokenValidator<>(
new JwtTimestampValidator(Duration.ofSeconds(60)),
@@ -383,7 +383,7 @@ Then, to add into a resource server, it's a matter of specifying the `ReactiveJw
@Bean
ReactiveJwtDecoder jwtDecoder() {
NimbusReactiveJwtDecoder jwtDecoder = (NimbusReactiveJwtDecoder)
- ReactiveJwtDecoders.withOidcIssuerLocation(issuerUri);
+ ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
OAuth2TokenValidator audienceValidator = new AudienceValidator();
OAuth2TokenValidator withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/crypto.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/crypto.adoc
index 8ed89233d9f..e2ec18ad03a 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/crypto.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/additional-topics/crypto.adoc
@@ -17,14 +17,16 @@ Encryptors are thread-safe.
[[spring-security-crypto-encryption-bytes]]
==== BytesEncryptor
-Use the Encryptors.standard factory method to construct a "standard" BytesEncryptor:
+Use the `Encryptors.stronger` factory method to construct a BytesEncryptor:
[source,java]
----
-Encryptors.standard("password", "salt");
+Encryptors.stronger("password", "salt");
----
-The "standard" encryption method is 256-bit AES using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2).
+The "stronger" encryption method creates an encryptor using 256 bit AES encryption with
+Galois Counter Mode (GCM).
+It derives the secret key using PKCS #5's PBKDF2 (Password-Based Key Derivation Function #2).
This method requires Java 6.
The password used to generate the SecretKey should be kept in a secure place and not be shared.
The salt is used to prevent dictionary attacks against the key in the event your encrypted data is compromised.
@@ -38,6 +40,11 @@ Such a salt may be generated using a KeyGenerator:
String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded
----
+Users may also use the `standard` encryption method, which is 256-bit AES in Cipher Block Chaining (CBC) Mode.
+This mode is not https://en.wikipedia.org/wiki/Authenticated_encryption[authenticated] and does not provide any
+guarantees about the authenticity of the data.
+For a more secure alternative, users should prefer `Encryptors.stronger`.
+
[[spring-security-crypto-encryption-text]]
==== TextEncryptor
Use the Encryptors.text factory method to construct a standard TextEncryptor:
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/technical-overview.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/technical-overview.adoc
index 6dfb93bece7..de0cedb91ee 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/technical-overview.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/architecture/technical-overview.adoc
@@ -156,7 +156,7 @@ Let's consider a standard authentication scenario that everyone is familiar with
. The user proceeds, potentially to perform some operation which is potentially protected by an access control mechanism which checks the required permissions for the operation against the current security context information.
-The first three items constitute the authentication process so we'll take a look at how these take place within Spring Security.
+The first four items constitute the authentication process so we'll take a look at how these take place within Spring Security.
. The username and password are obtained and combined into an instance of `UsernamePasswordAuthenticationToken` (an instance of the `Authentication` interface, which we saw earlier).
. The token is passed to an instance of `AuthenticationManager` for validation.
@@ -258,7 +258,7 @@ Or you might work for a company that has a legacy proprietary authentication sys
In situations like this it's quite easy to get Spring Security to work, and still provide authorization capabilities.
All you need to do is write a filter (or equivalent) that reads the third-party user information from a location, build a Spring Security-specific `Authentication` object, and put it into the `SecurityContextHolder`.
In this case you also need to think about things which are normally taken care of automatically by the built-in authentication infrastructure.
-For example, you might need to pre-emptively create an HTTP session to <>, before you write the response to the client footnote:[It isn't possible to create a session once the response has been committed.
+For example, you might need to pre-emptively create an HTTP session to <>, before you write the response to the client footnote:[It isn't possible to create a session once the response has been committed.].
If you're wondering how the `AuthenticationManager` is implemented in a real world example, we'll look at that in the <>.
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc
index b33d622e0b2..c2bcddb0593 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/authorization/architecture.adoc
@@ -41,7 +41,7 @@ A pre-invocation decision on whether the invocation is allowed to proceed is mad
[[authz-access-decision-manager]]
==== The AccessDecisionManager
The `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` and is responsible for making final access control decisions.
-the `AccessDecisionManager` interface contains three methods:
+The `AccessDecisionManager` interface contains three methods:
[source,java]
----
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc
index e5a34e66f24..f2b603bc2da 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/java-configuration.adoc
@@ -25,10 +25,10 @@ import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.configuration.*;
@EnableWebSecurity
-public class WebSecurityConfig implements WebMvcConfigurer {
+public class WebSecurityConfig {
@Bean
- public UserDetailsService userDetailsService() throws Exception {
+ public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
return manager;
@@ -131,7 +131,10 @@ public class MvcWebApplicationInitializer extends
== HttpSecurity
Thus far our <> only contains information about how to authenticate our users.
-How does Spring Security know that we want to require all users to be authenticated? How does Spring Security know we want to support form based authentication? The reason for this is that the `WebSecurityConfigurerAdapter` provides a default configuration in the `configure(HttpSecurity http)` method that looks like:
+How does Spring Security know that we want to require all users to be authenticated?
+How does Spring Security know we want to support form based authentication?
+Actually, there is an configuration class that is being invoked behind the scenes called `WebSecurityConfigurerAdapter`.
+It has a method called `configure` with the following default implementation:
[source,java]
----
@@ -172,9 +175,17 @@ I want to configure authorized requests __and__ configure form login __and__ con
You might be wondering where the login form came from when you were prompted to log in, since we made no mention of any HTML files or JSPs.
Since Spring Security's default configuration does not explicitly set a URL for the login page, Spring Security generates one automatically, based on the features that are enabled and using standard values for the URL which processes the submitted login, the default target URL the user will be sent to after logging in and so on.
-While the automatically generated log in page is convenient to get up and running quickly, most applications will want to provide their own log in page.
-To do so we can update our configuration as seen below:
+While the automatically generated log in page is convenient to get up and running quickly, most applications will want to provide their own login page.
+When we want to change the default configuration, we can customize the `WebSecurityConfigurerAdapter` that we mentioned earlier by extending it like so:
+
+[source,java]
+----
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+ // ...
+}
+----
+And then override the `configure` method as seen below:
[source,java]
----
@@ -719,8 +730,8 @@ Resource Server uses `JwtTimestampValidator` to verify a token's validity window
```java
@Bean
JwtDecoder jwtDecoder() {
- NimbusJwtDecoderJwkSupport jwtDecoder = (NimbusJwtDecoderJwkSupport)
- JwtDecoders.withOidcIssuerLocation(issuerUri);
+ NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
+ JwtDecoders.fromOidcIssuerLocation(issuerUri);
OAuth2TokenValidator withClockSkew = new DelegatingOAuth2TokenValidator<>(
new JwtTimestampValidator(Duration.ofSeconds(60)),
@@ -759,8 +770,8 @@ Then, to add into a resource server, it's a matter of specifying the `JwtDecoder
```java
@Bean
JwtDecoder jwtDecoder() {
- NimbusJwtDecoderJwkSupport jwtDecoder = (NimbusJwtDecoderJwkSupport)
- JwtDecoders.withOidcIssuerLocation(issuerUri);
+ NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
+ JwtDecoders.fromOidcIssuerLocation(issuerUri);
OAuth2TokenValidator audienceValidator = new AudienceValidator();
OAuth2TokenValidator withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
@@ -1055,7 +1066,7 @@ public BCryptPasswordEncoder passwordEncoder() {
== Multiple HttpSecurity
We can configure multiple HttpSecurity instances just as we can have multiple `` blocks.
-The key is to extend the `WebSecurityConfigurationAdapter` multiple times.
+The key is to extend the `WebSecurityConfigurerAdapter` multiple times.
For example, the following is an example of having a different configuration for URL's that start with `/api/`.
[source,java]
diff --git a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/namespace.adoc b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/namespace.adoc
index ff49f69556d..4891a18eb11 100644
--- a/docs/manual/src/docs/asciidoc/_includes/servlet/preface/namespace.adoc
+++ b/docs/manual/src/docs/asciidoc/_includes/servlet/preface/namespace.adoc
@@ -133,7 +133,7 @@ With the default configuration, this is typically a comma-separated list of role
The prefix "ROLE_" is a marker which indicates that a simple comparison with the user's authorities should be made.
In other words, a normal role-based check should be used.
Access-control in Spring Security is not limited to the use of simple roles (hence the use of the prefix to differentiate between different types of security attributes).
-We'll see later how the interpretation can vary footnote:[The interpretation of the comma-separated values in the `access` attribute depends on the implementation of the pass:specialcharacters,macros[<>] which is used.
+We'll see later how the interpretation can vary footnote:[The interpretation of the comma-separated values in the `access` attribute depends on the implementation of the <> which is used.].
In Spring Security 3.0, the attribute can also be populated with an pass:specialcharacters,macros[<>].
diff --git a/gradle.properties b/gradle.properties
index e2e850a9900..add72a99b14 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,3 @@
-gaeVersion=1.9.71
-springBootVersion=2.1.3.RELEASE
-version=5.1.5.RELEASE
+gaeVersion=1.9.80
+springBootVersion=2.1.14.RELEASE
+version=5.1.11.RELEASE
diff --git a/gradle/dependency-management.gradle b/gradle/dependency-management.gradle
index ac5c5a3576c..784f5905a8b 100644
--- a/gradle/dependency-management.gradle
+++ b/gradle/dependency-management.gradle
@@ -1,13 +1,13 @@
if (!project.hasProperty('reactorVersion')) {
- ext.reactorVersion = 'Californium-SR6'
+ ext.reactorVersion = 'Californium-SR18'
}
if (!project.hasProperty('springVersion')) {
- ext.springVersion = '5.1.6.RELEASE'
+ ext.springVersion = '5.1.15.RELEASE'
}
if (!project.hasProperty('springDataVersion')) {
- ext.springDataVersion = 'Lovelace-SR6'
+ ext.springDataVersion = 'Lovelace-SR17'
}
dependencyManagement {
@@ -17,18 +17,18 @@ dependencyManagement {
mavenBom "org.springframework.data:spring-data-releasetrain:${springDataVersion}"
}
dependencies {
- dependency 'cglib:cglib-nodep:3.2.10'
- dependency 'com.squareup.okhttp3:mockwebserver:3.12.2'
+ dependency 'cglib:cglib-nodep:3.2.12'
+ dependency 'com.squareup.okhttp3:mockwebserver:3.12.12'
dependency 'opensymphony:sitemesh:2.4.2'
dependency 'org.gebish:geb-spock:0.10.0'
dependency 'org.jasig.cas:cas-server-webapp:4.2.7'
- dependency 'org.powermock:powermock-api-mockito2:2.0.0'
- dependency 'org.powermock:powermock-api-support:2.0.0'
- dependency 'org.powermock:powermock-core:2.0.0'
- dependency 'org.powermock:powermock-module-junit4-common:2.0.0'
- dependency 'org.powermock:powermock-module-junit4:2.0.0'
- dependency 'org.powermock:powermock-reflect:2.0.0'
- dependency 'org.python:jython:2.5.0'
+ dependency 'org.powermock:powermock-api-mockito2:2.0.7'
+ dependency 'org.powermock:powermock-api-support:2.0.7'
+ dependency 'org.powermock:powermock-core:2.0.7'
+ dependency 'org.powermock:powermock-module-junit4-common:2.0.7'
+ dependency 'org.powermock:powermock-module-junit4:2.0.7'
+ dependency 'org.powermock:powermock-reflect:2.0.7'
+ dependency 'org.python:jython:2.5.3'
dependency 'org.spockframework:spock-core:1.0-groovy-2.4'
dependency 'org.spockframework:spock-spring:1.0-groovy-2.4'
}
@@ -40,27 +40,27 @@ dependencyManagement {
dependency 'asm:asm:3.1'
dependency 'ch.qos.logback:logback-classic:1.2.3'
dependency 'ch.qos.logback:logback-core:1.2.3'
- dependency 'com.fasterxml.jackson.core:jackson-annotations:2.9.8'
- dependency 'com.fasterxml.jackson.core:jackson-core:2.9.8'
- dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
+ dependency 'com.fasterxml.jackson.core:jackson-annotations:2.9.10'
+ dependency 'com.fasterxml.jackson.core:jackson-core:2.9.10'
+ dependency 'com.fasterxml.jackson.core:jackson-databind:2.9.10.2'
dependency 'com.fasterxml:classmate:1.3.4'
dependency 'com.github.stephenc.jcip:jcip-annotations:1.0-1'
- dependency 'com.google.appengine:appengine-api-1.0-sdk:1.9.64'
- dependency 'com.google.appengine:appengine-api-labs:1.9.64'
- dependency 'com.google.appengine:appengine-api-stubs:1.9.64'
- dependency 'com.google.appengine:appengine-testing:1.9.64'
- dependency 'com.google.appengine:appengine:1.9.63'
+ dependency 'com.google.appengine:appengine-api-1.0-sdk:1.9.80'
+ dependency 'com.google.appengine:appengine-api-labs:1.9.80'
+ dependency 'com.google.appengine:appengine-api-stubs:1.9.80'
+ dependency 'com.google.appengine:appengine-testing:1.9.80'
+ dependency 'com.google.appengine:appengine:1.9.80'
dependency 'com.google.code.gson:gson:2.8.2'
dependency 'com.google.guava:guava:20.0'
dependency 'com.google.inject:guice:3.0'
dependency 'com.nimbusds:lang-tag:1.4.3'
dependency 'com.nimbusds:nimbus-jose-jwt:6.0.2'
dependency 'com.nimbusds:oauth2-oidc-sdk:6.0'
- dependency 'com.squareup.okhttp3:okhttp:3.12.2'
+ dependency 'com.squareup.okhttp3:okhttp:3.12.12'
dependency 'com.squareup.okio:okio:1.13.0'
dependency 'com.sun.xml.bind:jaxb-core:2.3.0.1'
- dependency 'com.sun.xml.bind:jaxb-impl:2.3.0.1'
- dependency 'com.unboundid:unboundid-ldapsdk:4.0.10'
+ dependency 'com.sun.xml.bind:jaxb-impl:2.3.3'
+ dependency 'com.unboundid:unboundid-ldapsdk:4.0.14'
dependency 'com.vaadin.external.google:android-json:0.0.20131108.vaadin1'
dependency 'commons-cli:commons-cli:1.4'
dependency 'commons-codec:commons-codec:1.11'
@@ -127,7 +127,7 @@ dependencyManagement {
dependency 'org.apache.directory.shared:shared-cursor:0.9.15'
dependency 'org.apache.directory.shared:shared-ldap-constants:0.9.15'
dependency 'org.apache.directory.shared:shared-ldap:0.9.15'
- dependency 'org.apache.httpcomponents:httpclient:4.5.7'
+ dependency 'org.apache.httpcomponents:httpclient:4.5.12'
dependency 'org.apache.httpcomponents:httpcore:4.4.8'
dependency 'org.apache.httpcomponents:httpmime:4.5.3'
dependency 'org.apache.mina:mina-core:2.0.0-M6'
@@ -140,28 +140,28 @@ dependencyManagement {
dependency 'org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.0.44'
dependency 'org.apache.tomcat.embed:tomcat-embed-websocket:8.5.23'
dependency 'org.apache.tomcat:tomcat-annotations-api:8.5.23'
- dependency 'org.aspectj:aspectjrt:1.9.2'
- dependency 'org.aspectj:aspectjtools:1.9.2'
- dependency 'org.aspectj:aspectjweaver:1.9.2'
+ dependency 'org.aspectj:aspectjrt:1.9.5'
+ dependency 'org.aspectj:aspectjtools:1.9.5'
+ dependency 'org.aspectj:aspectjweaver:1.9.5'
dependency 'org.assertj:assertj-core:3.11.1'
dependency 'org.attoparser:attoparser:2.0.4.RELEASE'
- dependency 'org.bouncycastle:bcpkix-jdk15on:1.61'
+ dependency 'org.bouncycastle:bcpkix-jdk15on:1.64'
dependency 'org.bouncycastle:bcprov-jdk15on:1.58'
- dependency 'org.codehaus.groovy:groovy-all:2.4.14'
- dependency 'org.codehaus.groovy:groovy-json:2.4.14'
- dependency 'org.codehaus.groovy:groovy:2.4.14'
+ dependency 'org.codehaus.groovy:groovy-all:2.4.19'
+ dependency 'org.codehaus.groovy:groovy-json:2.4.19'
+ dependency 'org.codehaus.groovy:groovy:2.4.19'
dependency 'org.eclipse.jdt:ecj:3.12.3'
- dependency 'org.eclipse.jetty.websocket:websocket-api:9.4.12.v20180830'
- dependency 'org.eclipse.jetty.websocket:websocket-client:9.4.12.v20180830'
- dependency 'org.eclipse.jetty.websocket:websocket-common:9.4.12.v20180830'
- dependency 'org.eclipse.jetty:jetty-client:9.4.12.v20180830'
- dependency 'org.eclipse.jetty:jetty-http:9.4.12.v20180830'
- dependency 'org.eclipse.jetty:jetty-io:9.4.12.v20180830'
- dependency 'org.eclipse.jetty:jetty-security:9.4.12.v20180830'
- dependency 'org.eclipse.jetty:jetty-server:9.4.12.v20180830'
- dependency 'org.eclipse.jetty:jetty-servlet:9.4.12.v20180830'
- dependency 'org.eclipse.jetty:jetty-util:9.4.12.v20180830'
- dependency 'org.eclipse.jetty:jetty-xml:9.4.12.v20180830'
+ dependency 'org.eclipse.jetty.websocket:websocket-api:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty.websocket:websocket-client:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty.websocket:websocket-common:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty:jetty-client:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty:jetty-http:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty:jetty-io:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty:jetty-security:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty:jetty-server:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty:jetty-servlet:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty:jetty-util:9.4.27.v20200227'
+ dependency 'org.eclipse.jetty:jetty-xml:9.4.27.v20200227'
dependency 'org.eclipse.persistence:javax.persistence:2.2.1'
dependency 'org.gebish:geb-ast:0.10.0'
dependency 'org.gebish:geb-core:0.10.0'
@@ -170,9 +170,9 @@ dependencyManagement {
dependency 'org.hamcrest:hamcrest-core:1.3'
dependency 'org.hibernate.common:hibernate-commons-annotations:5.0.1.Final'
dependency 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'
- dependency 'org.hibernate:hibernate-core:5.2.17.Final'
- dependency 'org.hibernate:hibernate-entitymanager:5.3.9.Final'
- dependency 'org.hibernate:hibernate-validator:6.0.16.Final'
+ dependency 'org.hibernate:hibernate-core:5.2.18.Final'
+ dependency 'org.hibernate:hibernate-entitymanager:5.3.15.Final'
+ dependency 'org.hibernate:hibernate-validator:6.0.19.Final'
dependency 'org.hsqldb:hsqldb:2.4.1'
dependency 'org.jasig.cas.client:cas-client-core:3.5.1'
dependency 'org.javassist:javassist:3.22.0-CR2'
@@ -183,17 +183,17 @@ dependencyManagement {
dependency 'org.objenesis:objenesis:2.6'
dependency 'org.openid4java:openid4java-nodeps:0.9.6'
dependency 'org.ow2.asm:asm:6.2.1'
- dependency 'org.reactivestreams:reactive-streams:1.0.1'
+ dependency 'org.reactivestreams:reactive-streams:1.0.3'
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.33.3'
dependency 'org.seleniumhq.selenium:selenium-api:3.141.59'
dependency 'org.seleniumhq.selenium:selenium-java:3.141.59'
dependency 'org.seleniumhq.selenium:selenium-support:3.141.59'
dependency 'org.skyscreamer:jsonassert:1.5.0'
- dependency 'org.slf4j:jcl-over-slf4j:1.7.26'
- dependency 'org.slf4j:jul-to-slf4j:1.7.26'
- dependency 'org.slf4j:log4j-over-slf4j:1.7.26'
- dependency 'org.slf4j:slf4j-api:1.7.26'
- dependency 'org.slf4j:slf4j-nop:1.7.26'
+ dependency 'org.slf4j:jcl-over-slf4j:1.7.30'
+ dependency 'org.slf4j:jul-to-slf4j:1.7.30'
+ dependency 'org.slf4j:log4j-over-slf4j:1.7.30'
+ dependency 'org.slf4j:slf4j-api:1.7.30'
+ dependency 'org.slf4j:slf4j-nop:1.7.30'
dependency 'org.sonatype.sisu.inject:cglib:2.2.1-v20090111'
dependency 'org.springframework.ldap:spring-ldap-core:2.3.2.RELEASE'
dependency 'org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE'
diff --git a/ldap/src/integration-test/java/org/springframework/security/ldap/server/UnboundIdContainerLdifTests.java b/ldap/src/integration-test/java/org/springframework/security/ldap/server/UnboundIdContainerLdifTests.java
new file mode 100644
index 00000000000..a407a244e80
--- /dev/null
+++ b/ldap/src/integration-test/java/org/springframework/security/ldap/server/UnboundIdContainerLdifTests.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2002-2020 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.ldap.server;
+
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.ldap.core.ContextSource;
+import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
+import org.springframework.security.ldap.SpringSecurityLdapTemplate;
+
+import javax.annotation.PreDestroy;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
+
+/**
+ * Tests for {@link UnboundIdContainer}, specifically relating to LDIF file detection.
+ *
+ * @author Eleftheria Stein
+ */
+public class UnboundIdContainerLdifTests {
+
+ AnnotationConfigApplicationContext appCtx;
+
+ @After
+ public void closeAppContext() {
+ if (appCtx != null) {
+ appCtx.close();
+ appCtx = null;
+ }
+ }
+
+ @Test
+ public void unboundIdContainerWhenCustomLdifNameThenLdifLoaded() {
+ appCtx = new AnnotationConfigApplicationContext(CustomLdifConfig.class);
+
+ DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
+ .getBean(ContextSource.class);
+
+ SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(contextSource);
+ assertThat(template.compare("uid=bob,ou=people", "uid", "bob")).isTrue();
+ }
+
+ @Configuration
+ static class CustomLdifConfig {
+ private UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org",
+ "classpath:test-server.ldif");
+
+ @Bean
+ UnboundIdContainer ldapContainer() {
+ this.container.setPort(0);
+ return this.container;
+ }
+
+ @Bean
+ ContextSource contextSource(UnboundIdContainer container) {
+ return new DefaultSpringSecurityContextSource("ldap://127.0.0.1:"
+ + container.getPort() + "/dc=springframework,dc=org");
+ }
+
+ @PreDestroy
+ void shutdown() {
+ this.container.stop();
+ }
+ }
+
+ @Test
+ public void unboundIdContainerWhenWildcardLdifNameThenLdifLoaded() {
+ appCtx = new AnnotationConfigApplicationContext(WildcardLdifConfig.class);
+
+ DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
+ .getBean(ContextSource.class);
+
+ SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(contextSource);
+ assertThat(template.compare("uid=bob,ou=people", "uid", "bob")).isTrue();
+ }
+
+ @Configuration
+ static class WildcardLdifConfig {
+ private UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org",
+ "classpath*:test-server.ldif");
+
+ @Bean
+ UnboundIdContainer ldapContainer() {
+ this.container.setPort(0);
+ return this.container;
+ }
+
+ @Bean
+ ContextSource contextSource(UnboundIdContainer container) {
+ return new DefaultSpringSecurityContextSource("ldap://127.0.0.1:"
+ + container.getPort() + "/dc=springframework,dc=org");
+ }
+
+ @PreDestroy
+ void shutdown() {
+ this.container.stop();
+ }
+ }
+
+ @Test
+ public void unboundIdContainerWhenMalformedLdifThenException() {
+ try {
+ appCtx = new AnnotationConfigApplicationContext(MalformedLdifConfig.class);
+ failBecauseExceptionWasNotThrown(IllegalStateException.class);
+ } catch (Exception e) {
+ assertThat(e.getCause()).isInstanceOf(IllegalStateException.class);
+ assertThat(e.getMessage()).contains("Unable to load LDIF classpath:test-server-malformed.txt");
+ }
+ }
+
+ @Configuration
+ static class MalformedLdifConfig {
+ private UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org",
+ "classpath:test-server-malformed.txt");
+
+ @Bean
+ UnboundIdContainer ldapContainer() {
+ this.container.setPort(0);
+ return this.container;
+ }
+
+ @PreDestroy
+ void shutdown() {
+ this.container.stop();
+ }
+ }
+}
diff --git a/ldap/src/integration-test/resources/test-server-malformed.txt b/ldap/src/integration-test/resources/test-server-malformed.txt
new file mode 100644
index 00000000000..e24b511f763
--- /dev/null
+++ b/ldap/src/integration-test/resources/test-server-malformed.txt
@@ -0,0 +1,9 @@
+dn: ou=groups,dc=springframework,dc=org
+objectclass: top
+objectclass: organizationalUnit
+ou: groups
+
+dn ou=subgroups,ou=groups,dc=springframework,dc=org
+objectclass: top
+objectclass: organizationalUnit
+ou: subgroups
diff --git a/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java b/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java
index 863de6bb295..334e89b739e 100644
--- a/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java
+++ b/ldap/src/main/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.java
@@ -16,6 +16,7 @@
package org.springframework.security.ldap.authentication.ad;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.ldap.CommunicationException;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.support.DefaultDirObjectFactory;
@@ -24,6 +25,7 @@
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
@@ -142,12 +144,15 @@ protected DirContextOperations doAuthentication(
UsernamePasswordAuthenticationToken auth) {
String username = auth.getName();
String password = (String) auth.getCredentials();
-
- DirContext ctx = bindAsUser(username, password);
+ DirContext ctx = null;
try {
+ ctx = bindAsUser(username, password);
return searchForUser(ctx, username);
}
+ catch (CommunicationException e) {
+ throw badLdapConnection(e);
+ }
catch (NamingException e) {
logger.error("Failed to locate directory entry for authenticated user: "
+ username, e);
@@ -210,8 +215,7 @@ private DirContext bindAsUser(String username, String password) {
|| (e instanceof OperationNotSupportedException)) {
handleBindException(bindPrincipal, e);
throw badCredentials(e);
- }
- else {
+ } else {
throw LdapUtils.convertLdapException(e);
}
}
@@ -313,6 +317,12 @@ private BadCredentialsException badCredentials(Throwable cause) {
return (BadCredentialsException) badCredentials().initCause(cause);
}
+ private InternalAuthenticationServiceException badLdapConnection(Throwable cause) {
+ return new InternalAuthenticationServiceException(messages.getMessage(
+ "LdapAuthenticationProvider.badLdapConnection",
+ "Connection to LDAP server failed."), cause);
+ }
+
private DirContextOperations searchForUser(DirContext context, String username)
throws NamingException {
SearchControls searchControls = new SearchControls();
@@ -327,6 +337,9 @@ private DirContextOperations searchForUser(DirContext context, String username)
searchControls, searchRoot, searchFilter,
new Object[] { bindPrincipal, username });
}
+ catch (CommunicationException ldapCommunicationException) {
+ throw badLdapConnection(ldapCommunicationException);
+ }
catch (IncorrectResultSizeDataAccessException incorrectResults) {
// Search should never return multiple results if properly configured - just
// rethrow
diff --git a/ldap/src/main/java/org/springframework/security/ldap/server/UnboundIdContainer.java b/ldap/src/main/java/org/springframework/security/ldap/server/UnboundIdContainer.java
index bf9b7b4820a..d620c5e986f 100644
--- a/ldap/src/main/java/org/springframework/security/ldap/server/UnboundIdContainer.java
+++ b/ldap/src/main/java/org/springframework/security/ldap/server/UnboundIdContainer.java
@@ -114,10 +114,10 @@ public void start() {
private void importLdif(InMemoryDirectoryServer directoryServer) {
if (StringUtils.hasText(this.ldif)) {
- Resource resource = this.context.getResource(this.ldif);
try {
- if (resource.exists()) {
- try (InputStream inputStream = resource.getInputStream()) {
+ Resource[] resources = this.context.getResources(this.ldif);
+ if (resources.length > 0 && resources[0].exists()) {
+ try (InputStream inputStream = resources[0].getInputStream()) {
directoryServer.importFromLDIF(false, new LDIFReader(inputStream));
}
}
diff --git a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java
index 5152bdbf11d..ba9e0c03bbc 100644
--- a/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java
+++ b/ldap/src/test/java/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProviderTests.java
@@ -32,6 +32,7 @@
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
+import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
@@ -58,6 +59,9 @@
* @author Rob Winch
*/
public class ActiveDirectoryLdapAuthenticationProviderTests {
+ public static final String EXISTING_LDAP_PROVIDER = "ldap://192.168.1.200/";
+ public static final String NON_EXISTING_LDAP_PROVIDER = "ldap://192.168.1.201/";
+
@Rule
public ExpectedException thrown = ExpectedException.none();
@@ -378,17 +382,29 @@ public void errorWithNoSubcodeIsHandledCleanly() throws Exception {
}
@Test(expected = org.springframework.ldap.CommunicationException.class)
- public void nonAuthenticationExceptionIsConvertedToSpringLdapException()
- throws Exception {
- provider.contextFactory = createContextFactoryThrowing(new CommunicationException(
- msg));
- provider.authenticate(joe);
+ public void nonAuthenticationExceptionIsConvertedToSpringLdapException() throws Throwable {
+ try {
+ provider.contextFactory = createContextFactoryThrowing(new CommunicationException(
+ msg));
+ provider.authenticate(joe);
+ } catch (InternalAuthenticationServiceException e) {
+ // Since GH-8418 ldap communication exception is wrapped into InternalAuthenticationServiceException.
+ // This test is about the wrapped exception, so we throw it.
+ throw e.getCause();
+ }
+ }
+
+ @Test(expected = org.springframework.security.authentication.InternalAuthenticationServiceException.class )
+ public void connectionExceptionIsWrappedInInternalException() throws Exception {
+ ActiveDirectoryLdapAuthenticationProvider noneReachableProvider = new ActiveDirectoryLdapAuthenticationProvider(
+ "mydomain.eu", NON_EXISTING_LDAP_PROVIDER, "dc=ad,dc=eu,dc=mydomain");
+ noneReachableProvider.doAuthentication(joe);
}
@Test
public void rootDnProvidedSeparatelyFromDomainAlsoWorks() throws Exception {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(
- "mydomain.eu", "ldap://192.168.1.200/", "dc=ad,dc=eu,dc=mydomain");
+ "mydomain.eu", EXISTING_LDAP_PROVIDER, "dc=ad,dc=eu,dc=mydomain");
checkAuthentication("dc=ad,dc=eu,dc=mydomain", provider);
}
@@ -414,8 +430,11 @@ public void contextEnvironmentPropertiesUsed() throws Exception {
provider.authenticate(joe);
fail("CommunicationException was expected with a root cause of ClassNotFoundException");
}
- catch (org.springframework.ldap.CommunicationException expected) {
- assertThat(expected.getRootCause()).isInstanceOf(ClassNotFoundException.class);
+ catch (InternalAuthenticationServiceException expected) {
+ assertThat(expected.getCause()).isInstanceOf(org.springframework.ldap.CommunicationException.class);
+ org.springframework.ldap.CommunicationException cause =
+ (org.springframework.ldap.CommunicationException) expected.getCause();
+ assertThat(cause.getRootCause()).isInstanceOf(ClassNotFoundException.class);
}
}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java
index 938fd9c2155..fc5fb598b37 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -73,7 +73,8 @@ public Authentication authenticate(Authentication authentication) throws Authent
authorizationCodeAuthentication.getClientRegistration(),
authorizationCodeAuthentication.getAuthorizationExchange(),
accessTokenResponse.getAccessToken(),
- accessTokenResponse.getRefreshToken());
+ accessTokenResponse.getRefreshToken(),
+ accessTokenResponse.getAdditionalParameters());
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
return authenticationResult;
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationExchangeValidator.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationExchangeValidator.java
index 37d6d8115b4..a240e0521a8 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationExchangeValidator.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationExchangeValidator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,6 @@
*/
final class OAuth2AuthorizationExchangeValidator {
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
- private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
static void validate(OAuth2AuthorizationExchange authorizationExchange) {
OAuth2AuthorizationRequest authorizationRequest = authorizationExchange.getAuthorizationRequest();
@@ -44,10 +43,5 @@ static void validate(OAuth2AuthorizationExchange authorizationExchange) {
OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
throw new OAuth2AuthorizationException(oauth2Error);
}
-
- if (!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())) {
- OAuth2Error oauth2Error = new OAuth2Error(INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE);
- throw new OAuth2AuthorizationException(oauth2Error);
- }
}
}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java
index 02d4b5e7b1f..8d3b70234d8 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -28,7 +28,6 @@
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
import org.springframework.security.oauth2.core.OAuth2Error;
-import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.util.Assert;
@@ -60,7 +59,7 @@
* @see Section 4.1.4 Access Token Response
*/
public class OAuth2LoginAuthenticationProvider implements AuthenticationProvider {
- private final OAuth2AccessTokenResponseClient accessTokenResponseClient;
+ private final OAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider;
private final OAuth2UserService userService;
private GrantedAuthoritiesMapper authoritiesMapper = (authorities -> authorities);
@@ -74,59 +73,54 @@ public OAuth2LoginAuthenticationProvider(
OAuth2AccessTokenResponseClient accessTokenResponseClient,
OAuth2UserService userService) {
- Assert.notNull(accessTokenResponseClient, "accessTokenResponseClient cannot be null");
Assert.notNull(userService, "userService cannot be null");
- this.accessTokenResponseClient = accessTokenResponseClient;
+ this.authorizationCodeAuthenticationProvider = new OAuth2AuthorizationCodeAuthenticationProvider(accessTokenResponseClient);
this.userService = userService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- OAuth2LoginAuthenticationToken authorizationCodeAuthentication =
+ OAuth2LoginAuthenticationToken loginAuthenticationToken =
(OAuth2LoginAuthenticationToken) authentication;
// Section 3.1.2.1 Authentication Request - https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
// scope
// REQUIRED. OpenID Connect requests MUST contain the "openid" scope value.
- if (authorizationCodeAuthentication.getAuthorizationExchange()
+ if (loginAuthenticationToken.getAuthorizationExchange()
.getAuthorizationRequest().getScopes().contains("openid")) {
// This is an OpenID Connect Authentication Request so return null
// and let OidcAuthorizationCodeAuthenticationProvider handle it instead
return null;
}
- OAuth2AccessTokenResponse accessTokenResponse;
+ OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthenticationToken;
try {
- OAuth2AuthorizationExchangeValidator.validate(
- authorizationCodeAuthentication.getAuthorizationExchange());
-
- accessTokenResponse = this.accessTokenResponseClient.getTokenResponse(
- new OAuth2AuthorizationCodeGrantRequest(
- authorizationCodeAuthentication.getClientRegistration(),
- authorizationCodeAuthentication.getAuthorizationExchange()));
-
+ authorizationCodeAuthenticationToken = (OAuth2AuthorizationCodeAuthenticationToken) this.authorizationCodeAuthenticationProvider
+ .authenticate(new OAuth2AuthorizationCodeAuthenticationToken(
+ loginAuthenticationToken.getClientRegistration(),
+ loginAuthenticationToken.getAuthorizationExchange()));
} catch (OAuth2AuthorizationException ex) {
OAuth2Error oauth2Error = ex.getError();
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
- OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken();
- Map additionalParameters = accessTokenResponse.getAdditionalParameters();
+ OAuth2AccessToken accessToken = authorizationCodeAuthenticationToken.getAccessToken();
+ Map additionalParameters = authorizationCodeAuthenticationToken.getAdditionalParameters();
OAuth2User oauth2User = this.userService.loadUser(new OAuth2UserRequest(
- authorizationCodeAuthentication.getClientRegistration(), accessToken, additionalParameters));
+ loginAuthenticationToken.getClientRegistration(), accessToken, additionalParameters));
Collection extends GrantedAuthority> mappedAuthorities =
this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(
- authorizationCodeAuthentication.getClientRegistration(),
- authorizationCodeAuthentication.getAuthorizationExchange(),
+ loginAuthenticationToken.getClientRegistration(),
+ loginAuthenticationToken.getAuthorizationExchange(),
oauth2User,
mappedAuthorities,
accessToken,
- accessTokenResponse.getRefreshToken());
- authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
+ authorizationCodeAuthenticationToken.getRefreshToken());
+ authenticationResult.setDetails(loginAuthenticationToken.getDetails());
return authenticationResult;
}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClient.java
index 9a64a9248dc..14c87ae0cf9 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClient.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,10 @@
*/
package org.springframework.security.oauth2.client.endpoint;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
@@ -65,15 +68,18 @@ public Mono getTokenResponse(OAuth2ClientCredentialsG
.headers(headers(clientRegistration))
.body(body)
.exchange()
- .flatMap(response ->{
- if (!response.statusCode().is2xxSuccessful()){
+ .flatMap(response -> {
+ HttpStatus status = HttpStatus.resolve(response.rawStatusCode());
+ if (status == null || !status.is2xxSuccessful()) {
// extract the contents of this into a method named oauth2AccessTokenResponse but has an argument for the response
- throw WebClientResponseException.create(response.rawStatusCode(),
+ return response.bodyToFlux(DataBuffer.class)
+ .map(DataBufferUtils::release)
+ .then(Mono.error(WebClientResponseException.create(response.rawStatusCode(),
"Cannot get token, expected 2xx HTTP Status code",
null,
null,
null
- );
+ )));
}
return response.body(oauth2AccessTokenResponse()); })
.map(response -> {
@@ -90,7 +96,6 @@ public Mono getTokenResponse(OAuth2ClientCredentialsG
private Consumer headers(ClientRegistration clientRegistration) {
return headers -> {
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
- headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
if (ClientAuthenticationMethod.BASIC.equals(clientRegistration.getClientAuthenticationMethod())) {
headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java
index de044d34216..7af5319acbd 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java
@@ -73,7 +73,6 @@
*/
public class OidcAuthorizationCodeAuthenticationProvider implements AuthenticationProvider {
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
- private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
private static final String INVALID_ID_TOKEN_ERROR_CODE = "invalid_id_token";
private static final String MISSING_SIGNATURE_VERIFIER_ERROR_CODE = "missing_signature_verifier";
private final OAuth2AccessTokenResponseClient accessTokenResponseClient;
@@ -127,11 +126,6 @@ public Authentication authenticate(Authentication authentication) throws Authent
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
- if (!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())) {
- OAuth2Error oauth2Error = new OAuth2Error(INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE);
- throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
- }
-
OAuth2AccessTokenResponse accessTokenResponse;
try {
accessTokenResponse = this.accessTokenResponseClient.getTokenResponse(
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManager.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManager.java
index ca8d16ad3d7..8d0c15bb956 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManager.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManager.java
@@ -76,7 +76,6 @@ public class OidcAuthorizationCodeReactiveAuthenticationManager implements
ReactiveAuthenticationManager {
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
- private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
private static final String INVALID_ID_TOKEN_ERROR_CODE = "invalid_id_token";
private static final String MISSING_SIGNATURE_VERIFIER_ERROR_CODE = "missing_signature_verifier";
@@ -127,11 +126,6 @@ public Mono authenticate(Authentication authentication) {
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
- if (!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())) {
- OAuth2Error oauth2Error = new OAuth2Error(INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE);
- throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
- }
-
OAuth2AuthorizationCodeGrantRequest authzRequest = new OAuth2AuthorizationCodeGrantRequest(
authorizationCodeAuthentication.getClientRegistration(),
authorizationCodeAuthentication.getAuthorizationExchange());
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistration.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistration.java
index f6170fad0b9..b17510ece7f 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistration.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistration.java
@@ -486,7 +486,7 @@ public ClientRegistration build() {
this.validateClientCredentialsGrantType();
} else if (AuthorizationGrantType.IMPLICIT.equals(this.authorizationGrantType)) {
this.validateImplicitGrantType();
- } else {
+ } else if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(this.authorizationGrantType)) {
this.validateAuthorizationCodeGrantType();
}
return this.create();
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/InMemoryReactiveClientRegistrationRepository.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/InMemoryReactiveClientRegistrationRepository.java
index 4d2db9d0a6e..98ba597c41c 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/InMemoryReactiveClientRegistrationRepository.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/InMemoryReactiveClientRegistrationRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,22 @@
*/
package org.springframework.security.oauth2.client.registration;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import reactor.core.publisher.Mono;
+import org.springframework.util.Assert;
+
/**
* A Reactive {@link ClientRegistrationRepository} that stores {@link ClientRegistration}(s) in-memory.
*
* @author Rob Winch
+ * @author Ebert Toribio
* @since 5.1
* @see ClientRegistrationRepository
* @see ClientRegistration
@@ -31,7 +38,7 @@
public final class InMemoryReactiveClientRegistrationRepository
implements ReactiveClientRegistrationRepository, Iterable {
- private final InMemoryClientRegistrationRepository delegate;
+ private final Map clientIdToClientRegistration;
/**
* Constructs an {@code InMemoryReactiveClientRegistrationRepository} using the provided parameters.
@@ -39,7 +46,12 @@ public final class InMemoryReactiveClientRegistrationRepository
* @param registrations the client registration(s)
*/
public InMemoryReactiveClientRegistrationRepository(ClientRegistration... registrations) {
- this.delegate = new InMemoryClientRegistrationRepository(registrations);
+ this(toList(registrations));
+ }
+
+ private static List toList(ClientRegistration... registrations) {
+ Assert.notEmpty(registrations, "registrations cannot be null or empty");
+ return Arrays.asList(registrations);
}
/**
@@ -48,12 +60,12 @@ public InMemoryReactiveClientRegistrationRepository(ClientRegistration... regist
* @param registrations the client registration(s)
*/
public InMemoryReactiveClientRegistrationRepository(List registrations) {
- this.delegate = new InMemoryClientRegistrationRepository(registrations);
+ this.clientIdToClientRegistration = toUnmodifiableConcurrentMap(registrations);
}
@Override
public Mono findByRegistrationId(String registrationId) {
- return Mono.justOrEmpty(this.delegate.findByRegistrationId(registrationId));
+ return Mono.justOrEmpty(this.clientIdToClientRegistration.get(registrationId));
}
/**
@@ -63,6 +75,20 @@ public Mono findByRegistrationId(String registrationId) {
*/
@Override
public Iterator iterator() {
- return delegate.iterator();
+ return this.clientIdToClientRegistration.values().iterator();
+ }
+
+ private static Map toUnmodifiableConcurrentMap(List registrations) {
+ Assert.notEmpty(registrations, "registrations cannot be null or empty");
+ ConcurrentHashMap result = new ConcurrentHashMap<>();
+ for (ClientRegistration registration : registrations) {
+ Assert.notNull(registration, "no registration can be null");
+ if (result.containsKey(registration.getRegistrationId())) {
+ throw new IllegalStateException(String.format("Duplicate key %s",
+ registration.getRegistrationId()));
+ }
+ result.put(registration.getRegistrationId(), registration);
+ }
+ return Collections.unmodifiableMap(result);
}
}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java
index 36f235a9f1e..3cd0467d989 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -41,6 +41,7 @@
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
+import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.FilterChain;
@@ -48,6 +49,11 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
/**
* A {@code Filter} for the OAuth 2.0 Authorization Code Grant,
@@ -132,24 +138,39 @@ public final void setAuthorizationRequestRepository(AuthorizationRequestReposito
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
- if (this.shouldProcessAuthorizationResponse(request)) {
- this.processAuthorizationResponse(request, response);
+ if (matchesAuthorizationResponse(request)) {
+ processAuthorizationResponse(request, response);
return;
}
filterChain.doFilter(request, response);
}
- private boolean shouldProcessAuthorizationResponse(HttpServletRequest request) {
+ private boolean matchesAuthorizationResponse(HttpServletRequest request) {
+ MultiValueMap params = OAuth2AuthorizationResponseUtils.toMultiMap(request.getParameterMap());
+ if (!OAuth2AuthorizationResponseUtils.isAuthorizationResponse(params)) {
+ return false;
+ }
OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestRepository.loadAuthorizationRequest(request);
if (authorizationRequest == null) {
return false;
}
- String requestUrl = UrlUtils.buildFullRequestUrl(request.getScheme(), request.getServerName(),
- request.getServerPort(), request.getRequestURI(), null);
- MultiValueMap params = OAuth2AuthorizationResponseUtils.toMultiMap(request.getParameterMap());
- if (requestUrl.equals(authorizationRequest.getRedirectUri()) &&
- OAuth2AuthorizationResponseUtils.isAuthorizationResponse(params)) {
+
+ // Compare redirect_uri
+ UriComponents requestUri = UriComponentsBuilder.fromUriString(UrlUtils.buildFullRequestUrl(request)).build();
+ UriComponents redirectUri = UriComponentsBuilder.fromUriString(authorizationRequest.getRedirectUri()).build();
+ Set>> requestUriParameters = new LinkedHashSet<>(requestUri.getQueryParams().entrySet());
+ Set>> redirectUriParameters = new LinkedHashSet<>(redirectUri.getQueryParams().entrySet());
+ // Remove the additional request parameters (if any) from the authorization response (request)
+ // before doing an exact comparison with the authorizationRequest.getRedirectUri() parameters (if any)
+ requestUriParameters.retainAll(redirectUriParameters);
+
+ if (Objects.equals(requestUri.getScheme(), redirectUri.getScheme()) &&
+ Objects.equals(requestUri.getUserInfo(), redirectUri.getUserInfo()) &&
+ Objects.equals(requestUri.getHost(), redirectUri.getHost()) &&
+ Objects.equals(requestUri.getPort(), redirectUri.getPort()) &&
+ Objects.equals(requestUri.getPath(), redirectUri.getPath()) &&
+ Objects.equals(requestUriParameters.toString(), redirectUriParameters.toString())) {
return true;
}
return false;
@@ -165,10 +186,7 @@ private void processAuthorizationResponse(HttpServletRequest request, HttpServle
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
MultiValueMap params = OAuth2AuthorizationResponseUtils.toMultiMap(request.getParameterMap());
- String redirectUri = UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
- .replaceQuery(null)
- .build()
- .toUriString();
+ String redirectUri = UrlUtils.buildFullRequestUrl(request);
OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(params, redirectUri);
OAuth2AuthorizationCodeAuthenticationToken authenticationRequest = new OAuth2AuthorizationCodeAuthenticationToken(
@@ -183,7 +201,7 @@ private void processAuthorizationResponse(HttpServletRequest request, HttpServle
} catch (OAuth2AuthorizationException ex) {
OAuth2Error error = ex.getError();
UriComponentsBuilder uriBuilder = UriComponentsBuilder
- .fromUriString(authorizationResponse.getRedirectUri())
+ .fromUriString(authorizationRequest.getRedirectUri())
.queryParam(OAuth2ParameterNames.ERROR, error.getErrorCode());
if (!StringUtils.isEmpty(error.getDescription())) {
uriBuilder.queryParam(OAuth2ParameterNames.ERROR_DESCRIPTION, error.getDescription());
@@ -206,7 +224,7 @@ private void processAuthorizationResponse(HttpServletRequest request, HttpServle
this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, currentAuthentication, request, response);
- String redirectUrl = authorizationResponse.getRedirectUri();
+ String redirectUrl = authorizationRequest.getRedirectUri();
SavedRequest savedRequest = this.requestCache.getRequest(request, response);
if (savedRequest != null) {
redirectUrl = savedRequest.getRedirectUrl();
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/OAuth2AuthorizedClientResolver.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/OAuth2AuthorizedClientResolver.java
index 77179560f55..bf13f5ca0dc 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/OAuth2AuthorizedClientResolver.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/OAuth2AuthorizedClientResolver.java
@@ -133,7 +133,7 @@ private Mono authorizedClientNotLoaded(String clientRegi
});
}
- private Mono extends OAuth2AuthorizedClient> clientCredentials(
+ Mono clientCredentials(
ClientRegistration clientRegistration, Authentication authentication, ServerWebExchange exchange) {
OAuth2ClientCredentialsGrantRequest grantRequest = new OAuth2ClientCredentialsGrantRequest(clientRegistration);
return this.clientCredentialsTokenResponseClient.getTokenResponse(grantRequest)
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java
index 9366d7ea6e3..f223822955c 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.java
@@ -85,8 +85,12 @@ public final class ServerOAuth2AuthorizedClientExchangeFilterFunction implements
private final OAuth2AuthorizedClientResolver authorizedClientResolver;
public ServerOAuth2AuthorizedClientExchangeFilterFunction(ReactiveClientRegistrationRepository clientRegistrationRepository, ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
+ this(authorizedClientRepository, new OAuth2AuthorizedClientResolver(clientRegistrationRepository, authorizedClientRepository));
+ }
+
+ ServerOAuth2AuthorizedClientExchangeFilterFunction(ServerOAuth2AuthorizedClientRepository authorizedClientRepository, OAuth2AuthorizedClientResolver authorizedClientResolver) {
this.authorizedClientRepository = authorizedClientRepository;
- this.authorizedClientResolver = new OAuth2AuthorizedClientResolver(clientRegistrationRepository, authorizedClientRepository);
+ this.authorizedClientResolver = authorizedClientResolver;
}
/**
@@ -246,13 +250,30 @@ private Mono createRequest(ClientRequest
}
private Mono refreshIfNecessary(ClientRequest request, ExchangeFunction next, OAuth2AuthorizedClient authorizedClient) {
- if (shouldRefresh(authorizedClient)) {
+ ClientRegistration clientRegistration = authorizedClient.getClientRegistration();
+ if (isClientCredentialsGrantType(clientRegistration) && hasTokenExpired(authorizedClient)) {
+ return createRequest(request)
+ .flatMap(r -> authorizeWithClientCredentials(clientRegistration, r));
+ } else if (shouldRefresh(authorizedClient)) {
return createRequest(request)
.flatMap(r -> refreshAuthorizedClient(next, authorizedClient, r));
}
return Mono.just(authorizedClient);
}
+ private boolean isClientCredentialsGrantType(ClientRegistration clientRegistration) {
+ return AuthorizationGrantType.CLIENT_CREDENTIALS.equals(clientRegistration.getAuthorizationGrantType());
+ }
+
+ private Mono authorizeWithClientCredentials(ClientRegistration clientRegistration, OAuth2AuthorizedClientResolver.Request request) {
+ Authentication authentication = request.getAuthentication();
+ ServerWebExchange exchange = request.getExchange();
+
+ return this.authorizedClientResolver.clientCredentials(clientRegistration, authentication, exchange).
+ flatMap(result -> this.authorizedClientRepository.saveAuthorizedClient(result, authentication, exchange)
+ .thenReturn(result));
+ }
+
private Mono refreshAuthorizedClient(ExchangeFunction next,
OAuth2AuthorizedClient authorizedClient, OAuth2AuthorizedClientResolver.Request r) {
ServerWebExchange exchange = r.getExchange();
@@ -285,6 +306,10 @@ private boolean shouldRefresh(OAuth2AuthorizedClient authorizedClient) {
if (refreshToken == null) {
return false;
}
+ return hasTokenExpired(authorizedClient);
+ }
+
+ private boolean hasTokenExpired(OAuth2AuthorizedClient authorizedClient) {
Instant now = this.clock.instant();
Instant expiresAt = authorizedClient.getAccessToken().getExpiresAt();
if (now.isAfter(expiresAt.minus(this.accessTokenExpiresSkew))) {
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java
index 8045e52e4cd..d3a5afa9731 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.java
@@ -22,6 +22,7 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
+import org.springframework.lang.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
@@ -103,6 +104,7 @@
*
*
* @author Rob Winch
+ * @author Roman Matiushchenko
* @since 5.1
*/
public final class ServletOAuth2AuthorizedClientExchangeFilterFunction
@@ -146,7 +148,7 @@ public ServletOAuth2AuthorizedClientExchangeFilterFunction(
@Override
public void afterPropertiesSet() throws Exception {
- Hooks.onLastOperator(REQUEST_CONTEXT_OPERATOR_KEY, Operators.lift((s, sub) -> createRequestContextSubscriber(sub)));
+ Hooks.onLastOperator(REQUEST_CONTEXT_OPERATOR_KEY, Operators.liftPublisher((s, sub) -> createRequestContextSubscriberIfNecessary(sub)));
}
@Override
@@ -288,32 +290,53 @@ public void setAccessTokenExpiresSkew(Duration accessTokenExpiresSkew) {
@Override
public Mono filter(ClientRequest request, ExchangeFunction next) {
- return Mono.just(request)
- .filter(req -> req.attribute(OAUTH2_AUTHORIZED_CLIENT_ATTR_NAME).isPresent())
- .switchIfEmpty(mergeRequestAttributesFromContext(request))
+ return mergeRequestAttributesIfNecessary(request)
.filter(req -> req.attribute(OAUTH2_AUTHORIZED_CLIENT_ATTR_NAME).isPresent())
.flatMap(req -> authorizedClient(req, next, getOAuth2AuthorizedClient(req.attributes())))
+ .switchIfEmpty(Mono.defer(() ->
+ mergeRequestAttributesIfNecessary(request)
+ .filter(req -> resolveClientRegistrationId(req.attributes()) != null)
+ .flatMap(this::authorizeClient)
+ ))
.map(authorizedClient -> bearer(request, authorizedClient))
.flatMap(next::exchange)
- .switchIfEmpty(next.exchange(request));
+ .switchIfEmpty(Mono.defer(() -> next.exchange(request)));
+ }
+
+ private Mono mergeRequestAttributesIfNecessary(ClientRequest request) {
+ if (!request.attribute(HTTP_SERVLET_REQUEST_ATTR_NAME).isPresent() ||
+ !request.attribute(HTTP_SERVLET_RESPONSE_ATTR_NAME).isPresent() ||
+ !request.attribute(AUTHENTICATION_ATTR_NAME).isPresent()) {
+ return mergeRequestAttributesFromContext(request);
+ } else {
+ return Mono.just(request);
+ }
}
private Mono mergeRequestAttributesFromContext(ClientRequest request) {
- return Mono.just(ClientRequest.from(request))
- .flatMap(builder -> Mono.subscriberContext()
- .map(ctx -> builder.attributes(attrs -> populateRequestAttributes(attrs, ctx))))
+ ClientRequest.Builder builder = ClientRequest.from(request);
+ return Mono.subscriberContext()
+ .map(ctx -> builder.attributes(attrs -> populateRequestAttributes(attrs, ctx)))
.map(ClientRequest.Builder::build);
}
private void populateRequestAttributes(Map attrs, Context ctx) {
- if (ctx.hasKey(HTTP_SERVLET_REQUEST_ATTR_NAME)) {
- attrs.putIfAbsent(HTTP_SERVLET_REQUEST_ATTR_NAME, ctx.get(HTTP_SERVLET_REQUEST_ATTR_NAME));
- }
- if (ctx.hasKey(HTTP_SERVLET_RESPONSE_ATTR_NAME)) {
- attrs.putIfAbsent(HTTP_SERVLET_RESPONSE_ATTR_NAME, ctx.get(HTTP_SERVLET_RESPONSE_ATTR_NAME));
- }
- if (ctx.hasKey(AUTHENTICATION_ATTR_NAME)) {
- attrs.putIfAbsent(AUTHENTICATION_ATTR_NAME, ctx.get(AUTHENTICATION_ATTR_NAME));
+ RequestContextDataHolder holder = RequestContextSubscriber.getRequestContext(ctx);
+ if (holder != null) {
+ HttpServletRequest request = holder.getRequest();
+ if (request != null) {
+ attrs.putIfAbsent(HTTP_SERVLET_REQUEST_ATTR_NAME, request);
+ }
+
+ HttpServletResponse response = holder.getResponse();
+ if (response != null) {
+ attrs.putIfAbsent(HTTP_SERVLET_RESPONSE_ATTR_NAME, response);
+ }
+
+ Authentication authentication = holder.getAuthentication();
+ if (authentication != null) {
+ attrs.putIfAbsent(AUTHENTICATION_ATTR_NAME, authentication);
+ }
}
populateDefaultOAuth2AuthorizedClient(attrs);
}
@@ -348,39 +371,50 @@ private void populateDefaultOAuth2AuthorizedClient(Map attrs) {
return;
}
+ String clientRegistrationId = resolveClientRegistrationId(attrs);
Authentication authentication = getAuthentication(attrs);
+ HttpServletRequest request = getRequest(attrs);
+ if (clientRegistrationId != null && authentication != null && request != null) {
+ OAuth2AuthorizedClient authorizedClient = this.authorizedClientRepository.loadAuthorizedClient(
+ clientRegistrationId, authentication, request);
+ if (authorizedClient != null) {
+ oauth2AuthorizedClient(authorizedClient).accept(attrs);
+ }
+ }
+ }
+
+ private String resolveClientRegistrationId(Map attrs) {
String clientRegistrationId = getClientRegistrationId(attrs);
if (clientRegistrationId == null) {
clientRegistrationId = this.defaultClientRegistrationId;
}
+ Authentication authentication = getAuthentication(attrs);
if (clientRegistrationId == null
&& this.defaultOAuth2AuthorizedClient
&& authentication instanceof OAuth2AuthenticationToken) {
clientRegistrationId = ((OAuth2AuthenticationToken) authentication).getAuthorizedClientRegistrationId();
}
- if (clientRegistrationId != null) {
- HttpServletRequest request = getRequest(attrs);
- OAuth2AuthorizedClient authorizedClient = this.authorizedClientRepository
- .loadAuthorizedClient(clientRegistrationId, authentication,
- request);
- if (authorizedClient == null) {
- authorizedClient = getAuthorizedClient(clientRegistrationId, attrs);
- }
- oauth2AuthorizedClient(authorizedClient).accept(attrs);
- }
+ return clientRegistrationId;
}
- private OAuth2AuthorizedClient getAuthorizedClient(String clientRegistrationId, Map attrs) {
+ private Mono authorizeClient(ClientRequest request) {
+ Map attrs = request.attributes();
+ String clientRegistrationId = resolveClientRegistrationId(attrs);
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(clientRegistrationId);
if (clientRegistration == null) {
throw new IllegalArgumentException("Could not find ClientRegistration with id " + clientRegistrationId);
}
if (AuthorizationGrantType.CLIENT_CREDENTIALS.equals(clientRegistration.getAuthorizationGrantType())) {
- return getAuthorizedClient(clientRegistration, attrs);
+ // NOTE: 'getAuthorizedClient()' needs to be executed on a dedicated thread via subscribeOn(Schedulers.elastic())
+ // since it performs a blocking I/O operation using RestTemplate internally
+ return Mono.fromSupplier(() -> getAuthorizedClient(clientRegistration, attrs)).subscribeOn(Schedulers.elastic());
}
throw new ClientAuthorizationRequiredException(clientRegistrationId);
}
+ private boolean isClientCredentialsGrantType(ClientRegistration clientRegistration) {
+ return AuthorizationGrantType.CLIENT_CREDENTIALS.equals(clientRegistration.getAuthorizationGrantType());
+ }
private OAuth2AuthorizedClient getAuthorizedClient(ClientRegistration clientRegistration,
Map attrs) {
@@ -409,7 +443,11 @@ private OAuth2AuthorizedClient getAuthorizedClient(ClientRegistration clientRegi
}
private Mono authorizedClient(ClientRequest request, ExchangeFunction next, OAuth2AuthorizedClient authorizedClient) {
- if (shouldRefresh(authorizedClient)) {
+ ClientRegistration clientRegistration = authorizedClient.getClientRegistration();
+ if (isClientCredentialsGrantType(clientRegistration) && hasTokenExpired(authorizedClient)) {
+ //Client credentials grant do not have refresh tokens but can expire so we need to get another one
+ return Mono.fromSupplier(() -> getAuthorizedClient(clientRegistration, request.attributes()));
+ } else if (shouldRefresh(authorizedClient)) {
return refreshAuthorizedClient(request, next, authorizedClient);
}
return Mono.just(authorizedClient);
@@ -454,6 +492,10 @@ private boolean shouldRefresh(OAuth2AuthorizedClient authorizedClient) {
if (refreshToken == null) {
return false;
}
+ return hasTokenExpired(authorizedClient);
+ }
+
+ private boolean hasTokenExpired(OAuth2AuthorizedClient authorizedClient) {
Instant now = this.clock.instant();
Instant expiresAt = authorizedClient.getAccessToken().getExpiresAt();
if (now.isAfter(expiresAt.minus(this.accessTokenExpiresSkew))) {
@@ -468,7 +510,7 @@ private ClientRequest bearer(ClientRequest request, OAuth2AuthorizedClient autho
.build();
}
- private CoreSubscriber createRequestContextSubscriber(CoreSubscriber delegate) {
+ CoreSubscriber createRequestContextSubscriberIfNecessary(CoreSubscriber delegate) {
HttpServletRequest request = null;
HttpServletResponse response = null;
ServletRequestAttributes requestAttributes =
@@ -478,6 +520,10 @@ private CoreSubscriber createRequestContextSubscriber(CoreSubscriber d
response = requestAttributes.getResponse();
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication == null && request == null && response == null) {
+ //do not need to create RequestContextSubscriber with empty data
+ return delegate;
+ }
return new RequestContextSubscriber<>(delegate, request, response, authentication);
}
@@ -555,34 +601,37 @@ private UnsupportedOperationException unsupported() {
}
}
- private static class RequestContextSubscriber implements CoreSubscriber {
- private static final String CONTEXT_DEFAULTED_ATTR_NAME = RequestContextSubscriber.class.getName().concat(".CONTEXT_DEFAULTED_ATTR_NAME");
+ static class RequestContextSubscriber implements CoreSubscriber {
+ static final String REQUEST_CONTEXT_DATA_HOLDER =
+ RequestContextSubscriber.class.getName().concat(".REQUEST_CONTEXT_DATA_HOLDER");
private final CoreSubscriber delegate;
- private final HttpServletRequest request;
- private final HttpServletResponse response;
- private final Authentication authentication;
+ private final Context context;
- private RequestContextSubscriber(CoreSubscriber delegate,
- HttpServletRequest request,
- HttpServletResponse response,
- Authentication authentication) {
+ RequestContextSubscriber(CoreSubscriber delegate,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ Authentication authentication) {
this.delegate = delegate;
- this.request = request;
- this.response = response;
- this.authentication = authentication;
+
+ Context parentContext = this.delegate.currentContext();
+ Context context;
+ if (parentContext.hasKey(REQUEST_CONTEXT_DATA_HOLDER)) {
+ context = parentContext;
+ } else {
+ context = parentContext.put(REQUEST_CONTEXT_DATA_HOLDER, new RequestContextDataHolder(request, response, authentication));
+ }
+
+ this.context = context;
+ }
+
+ @Nullable
+ private static RequestContextDataHolder getRequestContext(Context ctx) {
+ return ctx.getOrDefault(REQUEST_CONTEXT_DATA_HOLDER, null);
}
@Override
public Context currentContext() {
- Context context = this.delegate.currentContext();
- if (context.hasKey(CONTEXT_DEFAULTED_ATTR_NAME)) {
- return context;
- }
- return Context.of(
- CONTEXT_DEFAULTED_ATTR_NAME, Boolean.TRUE,
- HTTP_SERVLET_REQUEST_ATTR_NAME, this.request,
- HTTP_SERVLET_RESPONSE_ATTR_NAME, this.response,
- AUTHENTICATION_ATTR_NAME, this.authentication);
+ return this.context;
}
@Override
@@ -605,4 +654,33 @@ public void onComplete() {
this.delegate.onComplete();
}
}
+
+ static class RequestContextDataHolder {
+ private final HttpServletRequest request;
+ private final HttpServletResponse response;
+ private final Authentication authentication;
+
+ RequestContextDataHolder(@Nullable HttpServletRequest request,
+ @Nullable HttpServletResponse response,
+ @Nullable Authentication authentication) {
+ this.request = request;
+ this.response = response;
+ this.authentication = authentication;
+ }
+
+ @Nullable
+ private HttpServletRequest getRequest() {
+ return this.request;
+ }
+
+ @Nullable
+ private HttpServletResponse getResponse() {
+ return this.response;
+ }
+
+ @Nullable
+ private Authentication getAuthentication() {
+ return this.authentication;
+ }
+ }
}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolver.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolver.java
index ff9c0cd03d4..d52a7bd7856 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolver.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolver.java
@@ -18,7 +18,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
import org.springframework.security.crypto.keygen.StringKeyGenerator;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
@@ -149,7 +148,7 @@ private String expandRedirectUri(ServerHttpRequest request, ClientRegistration c
Map uriVariables = new HashMap<>();
uriVariables.put("registrationId", clientRegistration.getRegistrationId());
- String baseUrl = UriComponentsBuilder.fromHttpRequest(new ServerHttpRequestDecorator(request))
+ String baseUrl = UriComponentsBuilder.fromUri(request.getURI())
.replacePath(request.getPath().contextPath().value())
.replaceQuery(null)
.build()
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationCodeGrantWebFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationCodeGrantWebFilter.java
index 02e76b1a1a6..ecd9084744a 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationCodeGrantWebFilter.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationCodeGrantWebFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -35,14 +35,22 @@
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import org.springframework.security.web.server.authentication.ServerAuthenticationFailureHandler;
import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler;
-import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
+import org.springframework.web.util.UriComponents;
+import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
+import java.net.URI;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
/**
* A {@code Filter} for the OAuth 2.0 Authorization Code Grant,
* which handles the processing of the OAuth 2.0 Authorization Response.
@@ -71,6 +79,7 @@
*
*
* @author Rob Winch
+ * @author Joe Grandja
* @since 5.1
* @see OAuth2AuthorizationCodeAuthenticationToken
* @see org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeReactiveAuthenticationManager
@@ -89,6 +98,9 @@ public class OAuth2AuthorizationCodeGrantWebFilter implements WebFilter {
private final ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
+ private ServerAuthorizationRequestRepository authorizationRequestRepository =
+ new WebSessionOAuth2ServerAuthorizationRequestRepository();
+
private ServerAuthenticationSuccessHandler authenticationSuccessHandler;
private ServerAuthenticationConverter authenticationConverter;
@@ -109,7 +121,7 @@ public OAuth2AuthorizationCodeGrantWebFilter(
Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
this.authenticationManager = authenticationManager;
this.authorizedClientRepository = authorizedClientRepository;
- this.requiresAuthenticationMatcher = new PathPatternParserServerWebExchangeMatcher("/{action}/oauth2/code/{registrationId}");
+ this.requiresAuthenticationMatcher = this::matchesAuthorizationResponse;
this.authenticationConverter = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter(clientRegistrationRepository);
this.authenticationSuccessHandler = new RedirectServerAuthenticationSuccessHandler();
this.authenticationFailureHandler = (webFilterExchange, exception) -> Mono.error(exception);
@@ -124,7 +136,7 @@ public OAuth2AuthorizationCodeGrantWebFilter(
Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
this.authenticationManager = authenticationManager;
this.authorizedClientRepository = authorizedClientRepository;
- this.requiresAuthenticationMatcher = new PathPatternParserServerWebExchangeMatcher("/{action}/oauth2/code/{registrationId}");
+ this.requiresAuthenticationMatcher = this::matchesAuthorizationResponse;
this.authenticationConverter = authenticationConverter;
this.authenticationSuccessHandler = new RedirectServerAuthenticationSuccessHandler();
this.authenticationFailureHandler = (webFilterExchange, exception) -> Mono.error(exception);
@@ -133,10 +145,10 @@ public OAuth2AuthorizationCodeGrantWebFilter(
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
return this.requiresAuthenticationMatcher.matches(exchange)
- .filter( matchResult -> matchResult.isMatch())
- .flatMap( matchResult -> this.authenticationConverter.convert(exchange))
+ .filter(ServerWebExchangeMatcher.MatchResult::isMatch)
+ .flatMap(matchResult -> this.authenticationConverter.convert(exchange))
.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
- .flatMap( token -> authenticate(exchange, chain, token));
+ .flatMap(token -> authenticate(exchange, chain, token));
}
private Mono authenticate(ServerWebExchange exchange,
@@ -164,4 +176,36 @@ private Mono onAuthenticationSuccess(Authentication authentication, WebFil
.flatMap(principal -> this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, principal, webFilterExchange.getExchange()))
);
}
+
+ private Mono matchesAuthorizationResponse(ServerWebExchange exchange) {
+ return Mono.just(exchange)
+ .filter(exch -> OAuth2AuthorizationResponseUtils.isAuthorizationResponse(exch.getRequest().getQueryParams()))
+ .flatMap(exch -> this.authorizationRequestRepository.loadAuthorizationRequest(exchange)
+ .flatMap(authorizationRequest ->
+ matchesRedirectUri(exch.getRequest().getURI(), authorizationRequest.getRedirectUri())))
+ .switchIfEmpty(ServerWebExchangeMatcher.MatchResult.notMatch());
+ }
+
+ private static Mono matchesRedirectUri(
+ URI authorizationResponseUri, String authorizationRequestRedirectUri) {
+ UriComponents requestUri = UriComponentsBuilder.fromUri(authorizationResponseUri).build();
+ UriComponents redirectUri = UriComponentsBuilder.fromUriString(authorizationRequestRedirectUri).build();
+ Set>> requestUriParameters =
+ new LinkedHashSet<>(requestUri.getQueryParams().entrySet());
+ Set>> redirectUriParameters =
+ new LinkedHashSet<>(redirectUri.getQueryParams().entrySet());
+ // Remove the additional request parameters (if any) from the authorization response (request)
+ // before doing an exact comparison with the authorizationRequest.getRedirectUri() parameters (if any)
+ requestUriParameters.retainAll(redirectUriParameters);
+
+ if (Objects.equals(requestUri.getScheme(), redirectUri.getScheme()) &&
+ Objects.equals(requestUri.getUserInfo(), redirectUri.getUserInfo()) &&
+ Objects.equals(requestUri.getHost(), redirectUri.getHost()) &&
+ Objects.equals(requestUri.getPort(), redirectUri.getPort()) &&
+ Objects.equals(requestUri.getPath(), redirectUri.getPath()) &&
+ Objects.equals(requestUriParameters.toString(), redirectUriParameters.toString())) {
+ return ServerWebExchangeMatcher.MatchResult.match();
+ }
+ return ServerWebExchangeMatcher.MatchResult.notMatch();
+ }
}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/ServerOAuth2AuthorizationCodeAuthenticationTokenConverter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/ServerOAuth2AuthorizationCodeAuthenticationTokenConverter.java
index 4d5c04488bd..3d76bc390e6 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/ServerOAuth2AuthorizationCodeAuthenticationTokenConverter.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/ServerOAuth2AuthorizationCodeAuthenticationTokenConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -28,7 +28,6 @@
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import org.springframework.util.Assert;
-import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
@@ -103,14 +102,10 @@ private Mono authenticationRequest(S
}
private static OAuth2AuthorizationResponse convertResponse(ServerWebExchange exchange) {
- MultiValueMap queryParams = exchange.getRequest()
- .getQueryParams();
String redirectUri = UriComponentsBuilder.fromUri(exchange.getRequest().getURI())
- .query(null)
.build()
.toUriString();
-
return OAuth2AuthorizationResponseUtils
- .convert(queryParams, redirectUri);
+ .convert(exchange.getRequest().getQueryParams(), redirectUri);
}
}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/WebSessionOAuth2ServerAuthorizationRequestRepository.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/WebSessionOAuth2ServerAuthorizationRequestRepository.java
index c40a12234fd..2ad3026ca40 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/WebSessionOAuth2ServerAuthorizationRequestRepository.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/WebSessionOAuth2ServerAuthorizationRequestRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -85,6 +85,9 @@ public Mono removeAuthorizationRequest(
OAuth2AuthorizationRequest removedValue = stateToAuthzRequest.remove(state);
if (stateToAuthzRequest.isEmpty()) {
sessionAttrs.remove(this.sessionAttributeName);
+ } else if (removedValue != null) {
+ // gh-7327 Overwrite the existing Map to ensure the state is saved for distributed sessions
+ sessionAttrs.put(this.sessionAttributeName, stateToAuthzRequest);
}
if (removedValue == null) {
sink.complete();
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java
index 1888c9b429b..74019c7baa1 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -15,6 +15,10 @@
*/
package org.springframework.security.oauth2.client.authentication;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,13 +37,12 @@
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
-import java.util.Collections;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses.accessTokenResponse;
/**
* Tests for {@link OAuth2AuthorizationCodeAuthenticationProvider}.
@@ -108,18 +111,6 @@ public void authenticateWhenAuthorizationResponseStateNotEqualAuthorizationReque
}).isInstanceOf(OAuth2AuthorizationException.class).hasMessageContaining("invalid_state_parameter");
}
- @Test
- public void authenticateWhenAuthorizationResponseRedirectUriNotEqualAuthorizationRequestRedirectUriThenThrowOAuth2AuthorizationException() {
- when(this.authorizationRequest.getRedirectUri()).thenReturn("https://example.com");
- when(this.authorizationResponse.getRedirectUri()).thenReturn("https://example2.com");
-
- assertThatThrownBy(() -> {
- this.authenticationProvider.authenticate(
- new OAuth2AuthorizationCodeAuthenticationToken(
- this.clientRegistration, this.authorizationExchange));
- }).isInstanceOf(OAuth2AuthorizationException.class).hasMessageContaining("invalid_redirect_uri_parameter");
- }
-
@Test
public void authenticateWhenAuthorizationSuccessResponseThenExchangedForAccessToken() {
OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class);
@@ -142,4 +133,26 @@ public void authenticateWhenAuthorizationSuccessResponseThenExchangedForAccessTo
assertThat(authenticationResult.getAccessToken()).isEqualTo(accessToken);
assertThat(authenticationResult.getRefreshToken()).isEqualTo(refreshToken);
}
+
+ // gh-5368
+ @Test
+ public void authenticateWhenAuthorizationSuccessResponseThenAdditionalParametersIncluded() {
+ Map additionalParameters = new HashMap<>();
+ additionalParameters.put("param1", "value1");
+ additionalParameters.put("param2", "value2");
+
+ OAuth2AccessTokenResponse accessTokenResponse = accessTokenResponse().additionalParameters(additionalParameters)
+ .build();
+ when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
+
+ OAuth2AuthorizationExchange authorizationExchange = new OAuth2AuthorizationExchange(this.authorizationRequest,
+ this.authorizationResponse);
+
+ OAuth2AuthorizationCodeAuthenticationToken authentication = (OAuth2AuthorizationCodeAuthenticationToken) this.authenticationProvider
+ .authenticate(
+ new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, authorizationExchange));
+
+ assertThat(authentication.getAdditionalParameters())
+ .containsAllEntriesOf(accessTokenResponse.getAdditionalParameters());
+ }
}
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeReactiveAuthenticationManagerTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeReactiveAuthenticationManagerTests.java
index adb28dca3d4..8c3cc2e19e3 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeReactiveAuthenticationManagerTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeReactiveAuthenticationManagerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -80,13 +80,6 @@ public void authenticateWhenStateNotEqualThenOAuth2AuthorizationException() {
.isInstanceOf(OAuth2AuthorizationException.class);
}
- @Test
- public void authenticateWhenRedirectUriNotEqualThenOAuth2AuthorizationException() {
- this.authorizationRequest.redirectUri("https://example.org/notequal");
- assertThatCode(() -> authenticate())
- .isInstanceOf(OAuth2AuthorizationException.class);
- }
-
@Test
public void authenticateWhenValidThenSuccess() {
when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(this.tokenResponse.build()));
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java
index 98a2e241f2e..f8d15290079 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -154,18 +154,6 @@ public void authenticateWhenAuthorizationResponseStateNotEqualAuthorizationReque
new OAuth2LoginAuthenticationToken(this.clientRegistration, this.authorizationExchange));
}
- @Test
- public void authenticateWhenAuthorizationResponseRedirectUriNotEqualAuthorizationRequestRedirectUriThenThrowOAuth2AuthenticationException() {
- this.exception.expect(OAuth2AuthenticationException.class);
- this.exception.expectMessage(containsString("invalid_redirect_uri_parameter"));
-
- when(this.authorizationRequest.getRedirectUri()).thenReturn("https://example.com");
- when(this.authorizationResponse.getRedirectUri()).thenReturn("https://example2.com");
-
- this.authenticationProvider.authenticate(
- new OAuth2LoginAuthenticationToken(this.clientRegistration, this.authorizationExchange));
- }
-
@Test
public void authenticateWhenLoginSuccessThenReturnAuthentication() {
OAuth2AccessTokenResponse accessTokenResponse = this.accessTokenSuccessResponse();
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClientTests.java
index 8bcd8164a8c..096f9d8145a 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClientTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClientTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -95,9 +95,11 @@ public void getTokenResponseWhenPostThenSuccess() throws Exception {
OAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(registration);
OAuth2AccessTokenResponse response = this.client.getTokenResponse(request).block();
- String body = this.server.takeRequest().getUtf8Body();
+ RecordedRequest actualRequest = this.server.takeRequest();
+ String body = actualRequest.getUtf8Body();
assertThat(response.getAccessToken()).isNotNull();
+ assertThat(actualRequest.getHeader(HttpHeaders.AUTHORIZATION)).isNull();
assertThat(body).isEqualTo("grant_type=client_credentials&scope=read%3Auser&client_id=client-id&client_secret=client-secret");
}
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java
index 083247b76d7..d53f731a93c 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -169,18 +169,6 @@ public void authenticateWhenAuthorizationResponseStateNotEqualAuthorizationReque
new OAuth2LoginAuthenticationToken(this.clientRegistration, this.authorizationExchange));
}
- @Test
- public void authenticateWhenAuthorizationResponseRedirectUriNotEqualAuthorizationRequestRedirectUriThenThrowOAuth2AuthenticationException() {
- this.exception.expect(OAuth2AuthenticationException.class);
- this.exception.expectMessage(containsString("invalid_redirect_uri_parameter"));
-
- when(this.authorizationRequest.getRedirectUri()).thenReturn("https://example1.com");
- when(this.authorizationResponse.getRedirectUri()).thenReturn("https://example2.com");
-
- this.authenticationProvider.authenticate(
- new OAuth2LoginAuthenticationToken(this.clientRegistration, this.authorizationExchange));
- }
-
@Test
public void authenticateWhenTokenResponseDoesNotContainIdTokenThenThrowOAuth2AuthenticationException() {
this.exception.expect(OAuth2AuthenticationException.class);
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationTests.java
index 23059d595b4..208a6e63fa0 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationTests.java
@@ -535,4 +535,27 @@ public void buildWhenClientCredentialsGrantTokenUriIsNullThenThrowIllegalArgumen
.build()
).isInstanceOf(IllegalArgumentException.class);
}
+
+ @Test
+ public void buildWhenCustomGrantAllAttributesProvidedThenAllAttributesAreSet() {
+ AuthorizationGrantType customGrantType = new AuthorizationGrantType("CUSTOM");
+ ClientRegistration registration = ClientRegistration.withRegistrationId(REGISTRATION_ID)
+ .clientId(CLIENT_ID)
+ .clientSecret(CLIENT_SECRET)
+ .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
+ .authorizationGrantType(customGrantType)
+ .scope(SCOPES.toArray(new String[0]))
+ .tokenUri(TOKEN_URI)
+ .clientName(CLIENT_NAME)
+ .build();
+
+ assertThat(registration.getRegistrationId()).isEqualTo(REGISTRATION_ID);
+ assertThat(registration.getClientId()).isEqualTo(CLIENT_ID);
+ assertThat(registration.getClientSecret()).isEqualTo(CLIENT_SECRET);
+ assertThat(registration.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.BASIC);
+ assertThat(registration.getAuthorizationGrantType()).isEqualTo(customGrantType);
+ assertThat(registration.getScopes()).isEqualTo(SCOPES);
+ assertThat(registration.getProviderDetails().getTokenUri()).isEqualTo(TOKEN_URI);
+ assertThat(registration.getClientName()).isEqualTo(CLIENT_NAME);
+ }
}
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilterTests.java
index 4dd9e2fc0d3..3eec2d00515 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilterTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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,10 +18,6 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
@@ -39,36 +35,44 @@
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
-import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
-import org.springframework.security.oauth2.core.OAuth2RefreshToken;
-import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
+import org.springframework.security.web.util.UrlUtils;
+import org.springframework.util.CollectionUtils;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.springframework.security.oauth2.core.TestOAuth2AccessTokens.noScopes;
+import static org.springframework.security.oauth2.core.TestOAuth2RefreshTokens.refreshToken;
+import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationExchanges.success;
+import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests.request;
/**
* Tests for {@link OAuth2AuthorizationCodeGrantFilter}.
*
* @author Joe Grandja
*/
-@PowerMockIgnore("javax.security.*")
-@PrepareForTest({OAuth2AuthorizationRequest.class, OAuth2AuthorizationExchange.class, OAuth2AuthorizationCodeGrantFilter.class})
-@RunWith(PowerMockRunner.class)
public class OAuth2AuthorizationCodeGrantFilterTests {
private ClientRegistration registration1;
private String principalName1 = "principal-1";
@@ -132,8 +136,7 @@ public void doFilterWhenNotAuthorizationResponseThenNotProcessed() throws Except
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
// NOTE: A valid Authorization Response contains either a 'code' or 'error' parameter.
-
- HttpServletResponse response = mock(HttpServletResponse.class);
+ MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
this.filter.doFilter(request, response, filterChain);
@@ -143,94 +146,142 @@ public void doFilterWhenNotAuthorizationResponseThenNotProcessed() throws Except
@Test
public void doFilterWhenAuthorizationRequestNotFoundThenNotProcessed() throws Exception {
- String requestUri = "/path";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.addParameter(OAuth2ParameterNames.CODE, "code");
- request.addParameter(OAuth2ParameterNames.STATE, "state");
-
- HttpServletResponse response = mock(HttpServletResponse.class);
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest("/path");
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
+ MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
- this.filter.doFilter(request, response, filterChain);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@Test
- public void doFilterWhenAuthorizationResponseUrlDoesNotMatchAuthorizationRequestRedirectUriThenNotProcessed() throws Exception {
+ public void doFilterWhenAuthorizationRequestRedirectUriDoesNotMatchThenNotProcessed() throws Exception {
String requestUri = "/callback/client-1";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.addParameter(OAuth2ParameterNames.CODE, "code");
- request.addParameter(OAuth2ParameterNames.STATE, "state");
-
- HttpServletResponse response = mock(HttpServletResponse.class);
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest(requestUri);
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
+ authorizationResponse.setRequestURI(requestUri + "-no-match");
FilterChain filterChain = mock(FilterChain.class);
- this.setUpAuthorizationRequest(request, response, this.registration1);
- request.setRequestURI(requestUri + "-no-match");
-
- this.filter.doFilter(request, response, filterChain);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
}
+ // gh-7963
@Test
- public void doFilterWhenAuthorizationResponseValidThenAuthorizationRequestRemoved() throws Exception {
+ public void doFilterWhenAuthorizationRequestRedirectUriParametersMatchThenProcessed() throws Exception {
+ // 1) redirect_uri with query parameters
String requestUri = "/callback/client-1";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.addParameter(OAuth2ParameterNames.CODE, "code");
- request.addParameter(OAuth2ParameterNames.STATE, "state");
+ Map parameters = new LinkedHashMap<>();
+ parameters.put("param1", "value1");
+ parameters.put("param2", "value2");
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest(requestUri, parameters);
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
+ this.setUpAuthenticationResult(this.registration1);
+ FilterChain filterChain = mock(FilterChain.class);
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
+ verifyZeroInteractions(filterChain);
+
+ // 2) redirect_uri with query parameters AND authorization response additional parameters
+ Map additionalParameters = new LinkedHashMap<>();
+ additionalParameters.put("auth-param1", "value1");
+ additionalParameters.put("auth-param2", "value2");
+ response = new MockHttpServletResponse();
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
+ authorizationResponse = createAuthorizationResponse(authorizationRequest, additionalParameters);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
+ verifyZeroInteractions(filterChain);
+ }
+ // gh-7963
+ @Test
+ public void doFilterWhenAuthorizationRequestRedirectUriParametersDoesNotMatchThenNotProcessed() throws Exception {
+ String requestUri = "/callback/client-1";
+ Map parameters = new LinkedHashMap<>();
+ parameters.put("param1", "value1");
+ parameters.put("param2", "value2");
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest(requestUri, parameters);
MockHttpServletResponse response = new MockHttpServletResponse();
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
+ this.setUpAuthenticationResult(this.registration1);
FilterChain filterChain = mock(FilterChain.class);
- this.setUpAuthorizationRequest(request, response, this.registration1);
+ // 1) Parameter value
+ Map parametersNotMatch = new LinkedHashMap<>(parameters);
+ parametersNotMatch.put("param2", "value8");
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(
+ createAuthorizationRequest(requestUri, parametersNotMatch));
+ authorizationResponse.setSession(authorizationRequest.getSession());
+ this.filter.doFilter(authorizationResponse, response, filterChain);
+ verify(filterChain, times(1)).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
+
+ // 2) Parameter order
+ parametersNotMatch = new LinkedHashMap<>();
+ parametersNotMatch.put("param2", "value2");
+ parametersNotMatch.put("param1", "value1");
+ authorizationResponse = createAuthorizationResponse(
+ createAuthorizationRequest(requestUri, parametersNotMatch));
+ authorizationResponse.setSession(authorizationRequest.getSession());
+ this.filter.doFilter(authorizationResponse, response, filterChain);
+ verify(filterChain, times(2)).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
+
+ // 3) Parameter missing
+ parametersNotMatch = new LinkedHashMap<>(parameters);
+ parametersNotMatch.remove("param2");
+ authorizationResponse = createAuthorizationResponse(
+ createAuthorizationRequest(requestUri, parametersNotMatch));
+ authorizationResponse.setSession(authorizationRequest.getSession());
+ this.filter.doFilter(authorizationResponse, response, filterChain);
+ verify(filterChain, times(3)).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
+ }
+
+ @Test
+ public void doFilterWhenAuthorizationRequestMatchThenAuthorizationRequestRemoved() throws Exception {
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest("/callback/client-1");
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ FilterChain filterChain = mock(FilterChain.class);
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
- this.filter.doFilter(request, response, filterChain);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
- assertThat(this.authorizationRequestRepository.loadAuthorizationRequest(request)).isNull();
+ assertThat(this.authorizationRequestRepository.loadAuthorizationRequest(authorizationResponse)).isNull();
}
@Test
public void doFilterWhenAuthorizationFailsThenHandleOAuth2AuthorizationException() throws Exception {
- String requestUri = "/callback/client-1";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.addParameter(OAuth2ParameterNames.CODE, "code");
- request.addParameter(OAuth2ParameterNames.STATE, "state");
-
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest("/callback/client-1");
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
- this.setUpAuthorizationRequest(request, response, this.registration1);
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT);
when(this.authenticationManager.authenticate(any(Authentication.class)))
.thenThrow(new OAuth2AuthorizationException(error));
- this.filter.doFilter(request, response, filterChain);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost/callback/client-1?error=invalid_grant");
}
@Test
- public void doFilterWhenAuthorizationResponseSuccessThenAuthorizedClientSavedToService() throws Exception {
- String requestUri = "/callback/client-1";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.addParameter(OAuth2ParameterNames.CODE, "code");
- request.addParameter(OAuth2ParameterNames.STATE, "state");
-
+ public void doFilterWhenAuthorizationSucceedsThenAuthorizedClientSavedToService() throws Exception {
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest("/callback/client-1");
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
-
- this.setUpAuthorizationRequest(request, response, this.registration1);
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
- this.filter.doFilter(request, response, filterChain);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient(
this.registration1.getRegistrationId(), this.principalName1);
@@ -242,40 +293,31 @@ public void doFilterWhenAuthorizationResponseSuccessThenAuthorizedClientSavedToS
}
@Test
- public void doFilterWhenAuthorizationResponseSuccessThenRedirected() throws Exception {
- String requestUri = "/callback/client-1";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.addParameter(OAuth2ParameterNames.CODE, "code");
- request.addParameter(OAuth2ParameterNames.STATE, "state");
-
+ public void doFilterWhenAuthorizationSucceedsThenRedirected() throws Exception {
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest("/callback/client-1");
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
-
- this.setUpAuthorizationRequest(request, response, this.registration1);
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
- this.filter.doFilter(request, response, filterChain);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost/callback/client-1");
}
@Test
- public void doFilterWhenAuthorizationResponseSuccessHasSavedRequestThenRedirectedToSavedRequest() throws Exception {
+ public void doFilterWhenAuthorizationSucceedsAndHasSavedRequestThenRedirectToSavedRequest() throws Exception {
String requestUri = "/saved-request";
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
MockHttpServletResponse response = new MockHttpServletResponse();
RequestCache requestCache = new HttpSessionRequestCache();
requestCache.saveRequest(request, response);
-
- requestUri = "/callback/client-1";
- request.setRequestURI(requestUri);
+ request.setRequestURI("/callback/client-1");
request.addParameter(OAuth2ParameterNames.CODE, "code");
request.addParameter(OAuth2ParameterNames.STATE, "state");
-
FilterChain filterChain = mock(FilterChain.class);
-
this.setUpAuthorizationRequest(request, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
@@ -285,36 +327,30 @@ public void doFilterWhenAuthorizationResponseSuccessHasSavedRequestThenRedirecte
}
@Test
- public void doFilterWhenAuthorizationResponseSuccessAndAnonymousAccessThenAuthorizedClientSavedToHttpSession() throws Exception {
+ public void doFilterWhenAuthorizationSucceedsAndAnonymousAccessThenAuthorizedClientSavedToHttpSession() throws Exception {
AnonymousAuthenticationToken anonymousPrincipal =
new AnonymousAuthenticationToken("key-1234", "anonymousUser", AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
securityContext.setAuthentication(anonymousPrincipal);
SecurityContextHolder.setContext(securityContext);
- String requestUri = "/callback/client-1";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.addParameter(OAuth2ParameterNames.CODE, "code");
- request.addParameter(OAuth2ParameterNames.STATE, "state");
-
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest("/callback/client-1");
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
-
- this.setUpAuthorizationRequest(request, response, this.registration1);
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
- this.filter.doFilter(request, response, filterChain);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
OAuth2AuthorizedClient authorizedClient = this.authorizedClientRepository.loadAuthorizedClient(
- this.registration1.getRegistrationId(), anonymousPrincipal, request);
+ this.registration1.getRegistrationId(), anonymousPrincipal, authorizationResponse);
assertThat(authorizedClient).isNotNull();
-
assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1);
assertThat(authorizedClient.getPrincipalName()).isEqualTo(anonymousPrincipal.getName());
assertThat(authorizedClient.getAccessToken()).isNotNull();
- HttpSession session = request.getSession(false);
+ HttpSession session = authorizationResponse.getSession(false);
assertThat(session).isNotNull();
@SuppressWarnings("unchecked")
@@ -326,33 +362,27 @@ public void doFilterWhenAuthorizationResponseSuccessAndAnonymousAccessThenAuthor
}
@Test
- public void doFilterWhenAuthorizationResponseSuccessAndAnonymousAccessNullAuthenticationThenAuthorizedClientSavedToHttpSession() throws Exception {
+ public void doFilterWhenAuthorizationSucceedsAndAnonymousAccessNullAuthenticationThenAuthorizedClientSavedToHttpSession() throws Exception {
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
SecurityContextHolder.setContext(securityContext); // null Authentication
- String requestUri = "/callback/client-1";
- MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
- request.setServletPath(requestUri);
- request.addParameter(OAuth2ParameterNames.CODE, "code");
- request.addParameter(OAuth2ParameterNames.STATE, "state");
-
+ MockHttpServletRequest authorizationRequest = createAuthorizationRequest("/callback/client-1");
+ MockHttpServletRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
-
- this.setUpAuthorizationRequest(request, response, this.registration1);
+ this.setUpAuthorizationRequest(authorizationRequest, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
- this.filter.doFilter(request, response, filterChain);
+ this.filter.doFilter(authorizationResponse, response, filterChain);
OAuth2AuthorizedClient authorizedClient = this.authorizedClientRepository.loadAuthorizedClient(
- this.registration1.getRegistrationId(), null, request);
+ this.registration1.getRegistrationId(), null, authorizationResponse);
assertThat(authorizedClient).isNotNull();
-
assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1);
assertThat(authorizedClient.getPrincipalName()).isEqualTo("anonymousUser");
assertThat(authorizedClient.getAccessToken()).isNotNull();
- HttpSession session = request.getSession(false);
+ HttpSession session = authorizationResponse.getSession(false);
assertThat(session).isNotNull();
@SuppressWarnings("unchecked")
@@ -363,23 +393,57 @@ public void doFilterWhenAuthorizationResponseSuccessAndAnonymousAccessNullAuthen
assertThat(authorizedClients.values().iterator().next()).isSameAs(authorizedClient);
}
+ private static MockHttpServletRequest createAuthorizationRequest(String requestUri) {
+ return createAuthorizationRequest(requestUri, new LinkedHashMap<>());
+ }
+
+ private static MockHttpServletRequest createAuthorizationRequest(String requestUri, Map parameters) {
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
+ request.setServletPath(requestUri);
+ if (!CollectionUtils.isEmpty(parameters)) {
+ parameters.forEach(request::addParameter);
+ request.setQueryString(
+ parameters.entrySet().stream()
+ .map(e -> e.getKey() + "=" + e.getValue())
+ .collect(Collectors.joining("&")));
+ }
+ return request;
+ }
+
+ private static MockHttpServletRequest createAuthorizationResponse(MockHttpServletRequest authorizationRequest) {
+ return createAuthorizationResponse(authorizationRequest, new LinkedHashMap<>());
+ }
+
+ private static MockHttpServletRequest createAuthorizationResponse(
+ MockHttpServletRequest authorizationRequest, Map additionalParameters) {
+ MockHttpServletRequest authorizationResponse = new MockHttpServletRequest(
+ authorizationRequest.getMethod(), authorizationRequest.getRequestURI());
+ authorizationResponse.setServletPath(authorizationRequest.getRequestURI());
+ authorizationRequest.getParameterMap().forEach(authorizationResponse::addParameter);
+ authorizationResponse.addParameter(OAuth2ParameterNames.CODE, "code");
+ authorizationResponse.addParameter(OAuth2ParameterNames.STATE, "state");
+ additionalParameters.forEach(authorizationResponse::addParameter);
+ authorizationResponse.setQueryString(
+ authorizationResponse.getParameterMap().entrySet().stream()
+ .map(e -> e.getKey() + "=" + e.getValue()[0])
+ .collect(Collectors.joining("&")));
+ authorizationResponse.setSession(authorizationRequest.getSession());
+ return authorizationResponse;
+ }
+
private void setUpAuthorizationRequest(HttpServletRequest request, HttpServletResponse response,
ClientRegistration registration) {
Map additionalParameters = new HashMap<>();
additionalParameters.put(OAuth2ParameterNames.REGISTRATION_ID, registration.getRegistrationId());
- OAuth2AuthorizationRequest authorizationRequest = mock(OAuth2AuthorizationRequest.class);
- when(authorizationRequest.getAdditionalParameters()).thenReturn(additionalParameters);
- when(authorizationRequest.getRedirectUri()).thenReturn(request.getRequestURL().toString());
- when(authorizationRequest.getState()).thenReturn("state");
+ OAuth2AuthorizationRequest authorizationRequest = request()
+ .additionalParameters(additionalParameters)
+ .redirectUri(UrlUtils.buildFullRequestUrl(request)).build();
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
}
private void setUpAuthenticationResult(ClientRegistration registration) {
- OAuth2AuthorizationCodeAuthenticationToken authentication = mock(OAuth2AuthorizationCodeAuthenticationToken.class);
- when(authentication.getClientRegistration()).thenReturn(registration);
- when(authentication.getAuthorizationExchange()).thenReturn(mock(OAuth2AuthorizationExchange.class));
- when(authentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class));
- when(authentication.getRefreshToken()).thenReturn(mock(OAuth2RefreshToken.class));
+ OAuth2AuthorizationCodeAuthenticationToken authentication =
+ new OAuth2AuthorizationCodeAuthenticationToken(registration, success(), noScopes(), refreshToken());
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(authentication);
}
}
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunctionTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunctionTests.java
index a679a5996d5..a5c0e91f5b4 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunctionTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunctionTests.java
@@ -44,6 +44,7 @@
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
+import org.springframework.security.oauth2.client.web.reactive.function.client.OAuth2AuthorizedClientResolver.Request;
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
@@ -69,6 +70,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@@ -88,6 +90,9 @@ public class ServerOAuth2AuthorizedClientExchangeFilterFunctionTests {
@Mock
private ReactiveClientRegistrationRepository clientRegistrationRepository;
+ @Mock
+ private OAuth2AuthorizedClientResolver oAuth2AuthorizedClientResolver;
+
@Mock
private ServerWebExchange serverWebExchange;
@@ -149,6 +154,88 @@ public void filterWhenExistingAuthorizationThenSingleAuthorizationHeader() {
assertThat(headers.get(HttpHeaders.AUTHORIZATION)).containsOnly("Bearer " + this.accessToken.getTokenValue());
}
+ @Test
+ public void filterWhenClientCredentialsTokenExpiredThenGetNewToken() {
+ TestingAuthenticationToken authentication = new TestingAuthenticationToken("test", "this");
+ ClientRegistration registration = TestClientRegistrations.clientCredentials().build();
+ String clientRegistrationId = registration.getClientId();
+
+ this.function = new ServerOAuth2AuthorizedClientExchangeFilterFunction(this.authorizedClientRepository, this.oAuth2AuthorizedClientResolver);
+
+ OAuth2AccessToken newAccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
+ "new-token",
+ Instant.now(),
+ Instant.now().plus(Duration.ofDays(1)));
+ OAuth2AuthorizedClient newAuthorizedClient = new OAuth2AuthorizedClient(registration,
+ "principalName", newAccessToken, null);
+ Request r = new Request(clientRegistrationId, authentication, null);
+ when(this.oAuth2AuthorizedClientResolver.clientCredentials(any(), any(), any())).thenReturn(Mono.just(newAuthorizedClient));
+ when(this.oAuth2AuthorizedClientResolver.createDefaultedRequest(any(), any(), any())).thenReturn(Mono.just(r));
+
+ when(this.authorizedClientRepository.saveAuthorizedClient(any(), any(), any())).thenReturn(Mono.empty());
+
+ Instant issuedAt = Instant.now().minus(Duration.ofDays(1));
+ Instant accessTokenExpiresAt = issuedAt.plus(Duration.ofHours(1));
+
+ OAuth2AccessToken accessToken = new OAuth2AccessToken(this.accessToken.getTokenType(),
+ this.accessToken.getTokenValue(),
+ issuedAt,
+ accessTokenExpiresAt);
+
+
+ OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(registration,
+ "principalName", accessToken, null);
+ ClientRequest request = ClientRequest.create(GET, URI.create("https://example.com"))
+ .attributes(oauth2AuthorizedClient(authorizedClient))
+ .build();
+
+
+ this.function.filter(request, this.exchange)
+ .subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
+ .block();
+
+ verify(this.authorizedClientRepository).saveAuthorizedClient(any(), eq(authentication), any());
+ verify(this.oAuth2AuthorizedClientResolver).clientCredentials(any(), any(), any());
+ verify(this.oAuth2AuthorizedClientResolver).createDefaultedRequest(any(), any(), any());
+
+ List requests = this.exchange.getRequests();
+ assertThat(requests).hasSize(1);
+ ClientRequest request1 = requests.get(0);
+ assertThat(request1.headers().getFirst(HttpHeaders.AUTHORIZATION)).isEqualTo("Bearer new-token");
+ assertThat(request1.url().toASCIIString()).isEqualTo("https://example.com");
+ assertThat(request1.method()).isEqualTo(HttpMethod.GET);
+ assertThat(getBody(request1)).isEmpty();
+ }
+
+ @Test
+ public void filterWhenClientCredentialsTokenNotExpiredThenUseCurrentToken() {
+ TestingAuthenticationToken authentication = new TestingAuthenticationToken("test", "this");
+ ClientRegistration registration = TestClientRegistrations.clientCredentials().build();
+
+ this.function = new ServerOAuth2AuthorizedClientExchangeFilterFunction(this.authorizedClientRepository, this.oAuth2AuthorizedClientResolver);
+
+ OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(registration,
+ "principalName", this.accessToken, null);
+ ClientRequest request = ClientRequest.create(GET, URI.create("https://example.com"))
+ .attributes(oauth2AuthorizedClient(authorizedClient))
+ .build();
+
+ this.function.filter(request, this.exchange)
+ .subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication))
+ .block();
+
+ verify(this.oAuth2AuthorizedClientResolver, never()).clientCredentials(any(), any(), any());
+ verify(this.oAuth2AuthorizedClientResolver, never()).createDefaultedRequest(any(), any(), any());
+
+ List requests = this.exchange.getRequests();
+ assertThat(requests).hasSize(1);
+ ClientRequest request1 = requests.get(0);
+ assertThat(request1.headers().getFirst(HttpHeaders.AUTHORIZATION)).isEqualTo("Bearer token-0");
+ assertThat(request1.url().toASCIIString()).isEqualTo("https://example.com");
+ assertThat(request1.method()).isEqualTo(HttpMethod.GET);
+ assertThat(getBody(request1)).isEmpty();
+ }
+
@Test
public void filterWhenRefreshRequiredThenRefresh() {
when(this.authorizedClientRepository.saveAuthorizedClient(any(), any(), any())).thenReturn(Mono.empty());
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunctionITests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunctionITests.java
new file mode 100644
index 00000000000..7f963e53c81
--- /dev/null
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunctionITests.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2002-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.oauth2.client.web.reactive.function.client;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.security.authentication.TestingAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
+import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
+import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
+import org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository;
+import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
+import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.security.oauth2.core.OAuth2RefreshToken;
+import org.springframework.security.oauth2.core.TestOAuth2RefreshTokens;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.*;
+import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
+
+/**
+ * @author Joe Grandja
+ */
+public class ServletOAuth2AuthorizedClientExchangeFilterFunctionITests {
+ private ClientRegistrationRepository clientRegistrationRepository;
+ private OAuth2AuthorizedClientRepository authorizedClientRepository;
+ private ServletOAuth2AuthorizedClientExchangeFilterFunction authorizedClientFilter;
+ private MockWebServer server;
+ private String serverUrl;
+ private WebClient webClient;
+ private Authentication authentication;
+ private MockHttpServletRequest request;
+ private MockHttpServletResponse response;
+
+ @Before
+ public void setUp() throws Exception {
+ this.clientRegistrationRepository = mock(ClientRegistrationRepository.class);
+ final OAuth2AuthorizedClientRepository delegate = new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(
+ new InMemoryOAuth2AuthorizedClientService(this.clientRegistrationRepository));
+ this.authorizedClientRepository = spy(new OAuth2AuthorizedClientRepository() {
+ @Override
+ public T loadAuthorizedClient(String clientRegistrationId, Authentication principal, HttpServletRequest request) {
+ return delegate.loadAuthorizedClient(clientRegistrationId, principal, request);
+ }
+
+ @Override
+ public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal, HttpServletRequest request, HttpServletResponse response) {
+ delegate.saveAuthorizedClient(authorizedClient, principal, request, response);
+ }
+
+ @Override
+ public void removeAuthorizedClient(String clientRegistrationId, Authentication principal, HttpServletRequest request, HttpServletResponse response) {
+ delegate.removeAuthorizedClient(clientRegistrationId, principal, request, response);
+ }
+ });
+ this.authorizedClientFilter = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
+ this.clientRegistrationRepository, this.authorizedClientRepository);
+ this.authorizedClientFilter.afterPropertiesSet();
+ this.server = new MockWebServer();
+ this.server.start();
+ this.serverUrl = this.server.url("/").toString();
+ this.webClient = WebClient.builder()
+ .apply(this.authorizedClientFilter.oauth2Configuration())
+ .build();
+ this.authentication = new TestingAuthenticationToken("principal", "password");
+ SecurityContextHolder.getContext().setAuthentication(this.authentication);
+ this.request = new MockHttpServletRequest();
+ this.response = new MockHttpServletResponse();
+ RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(this.request, this.response));
+ }
+
+ @After
+ public void cleanup() throws Exception {
+ this.authorizedClientFilter.destroy();
+ this.server.shutdown();
+ SecurityContextHolder.clearContext();
+ RequestContextHolder.resetRequestAttributes();
+ }
+
+ @Test
+ public void requestWhenNotAuthorizedThenAuthorizeAndSendRequest() {
+ String accessTokenResponse = "{\n" +
+ " \"access_token\": \"access-token-1234\",\n" +
+ " \"token_type\": \"bearer\",\n" +
+ " \"expires_in\": \"3600\",\n" +
+ " \"scope\": \"read write\"\n" +
+ "}\n";
+ String clientResponse = "{\n" +
+ " \"attribute1\": \"value1\",\n" +
+ " \"attribute2\": \"value2\"\n" +
+ "}\n";
+
+ this.server.enqueue(jsonResponse(accessTokenResponse));
+ this.server.enqueue(jsonResponse(clientResponse));
+
+ ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials().tokenUri(this.serverUrl).build();
+ when(this.clientRegistrationRepository.findByRegistrationId(eq(clientRegistration.getRegistrationId()))).thenReturn(clientRegistration);
+
+ this.webClient
+ .get()
+ .uri(this.serverUrl)
+ .attributes(clientRegistrationId(clientRegistration.getRegistrationId()))
+ .retrieve()
+ .bodyToMono(String.class)
+ .block();
+
+ assertThat(this.server.getRequestCount()).isEqualTo(2);
+
+ ArgumentCaptor authorizedClientCaptor = ArgumentCaptor.forClass(OAuth2AuthorizedClient.class);
+ verify(this.authorizedClientRepository).saveAuthorizedClient(
+ authorizedClientCaptor.capture(), eq(this.authentication), eq(this.request), eq(this.response));
+ assertThat(authorizedClientCaptor.getValue().getClientRegistration()).isSameAs(clientRegistration);
+ }
+
+ @Test
+ public void requestWhenAuthorizedButExpiredThenRefreshAndSendRequest() {
+ String accessTokenResponse = "{\n" +
+ " \"access_token\": \"refreshed-access-token\",\n" +
+ " \"token_type\": \"bearer\",\n" +
+ " \"expires_in\": \"3600\"\n" +
+ "}\n";
+ String clientResponse = "{\n" +
+ " \"attribute1\": \"value1\",\n" +
+ " \"attribute2\": \"value2\"\n" +
+ "}\n";
+
+ this.server.enqueue(jsonResponse(accessTokenResponse));
+ this.server.enqueue(jsonResponse(clientResponse));
+
+ ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().tokenUri(this.serverUrl).build();
+ when(this.clientRegistrationRepository.findByRegistrationId(eq(clientRegistration.getRegistrationId()))).thenReturn(clientRegistration);
+
+ Instant issuedAt = Instant.now().minus(Duration.ofDays(1));
+ Instant expiresAt = issuedAt.plus(Duration.ofHours(1));
+ OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
+ "expired-access-token", issuedAt, expiresAt, new HashSet<>(Arrays.asList("read", "write")));
+ OAuth2RefreshToken refreshToken = TestOAuth2RefreshTokens.refreshToken();
+ OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
+ clientRegistration, this.authentication.getName(), accessToken, refreshToken);
+ doReturn(authorizedClient).when(this.authorizedClientRepository).loadAuthorizedClient(
+ eq(clientRegistration.getRegistrationId()), eq(this.authentication), eq(this.request));
+
+ this.webClient
+ .get()
+ .uri(this.serverUrl)
+ .attributes(clientRegistrationId(clientRegistration.getRegistrationId()))
+ .retrieve()
+ .bodyToMono(String.class)
+ .block();
+
+ assertThat(this.server.getRequestCount()).isEqualTo(2);
+
+ ArgumentCaptor authorizedClientCaptor = ArgumentCaptor.forClass(OAuth2AuthorizedClient.class);
+ verify(this.authorizedClientRepository).saveAuthorizedClient(
+ authorizedClientCaptor.capture(), eq(this.authentication), eq(this.request), eq(this.response));
+ OAuth2AuthorizedClient refreshedAuthorizedClient = authorizedClientCaptor.getValue();
+ assertThat(refreshedAuthorizedClient.getClientRegistration()).isSameAs(clientRegistration);
+ assertThat(refreshedAuthorizedClient.getAccessToken().getTokenValue()).isEqualTo("refreshed-access-token");
+ }
+
+ @Test
+ public void requestMultipleWhenNoneAuthorizedThenAuthorizeAndSendRequest() {
+ String accessTokenResponse = "{\n" +
+ " \"access_token\": \"access-token-1234\",\n" +
+ " \"token_type\": \"bearer\",\n" +
+ " \"expires_in\": \"3600\",\n" +
+ " \"scope\": \"read write\"\n" +
+ "}\n";
+ String clientResponse = "{\n" +
+ " \"attribute1\": \"value1\",\n" +
+ " \"attribute2\": \"value2\"\n" +
+ "}\n";
+
+ // Client 1
+ this.server.enqueue(jsonResponse(accessTokenResponse));
+ this.server.enqueue(jsonResponse(clientResponse));
+
+ ClientRegistration clientRegistration1 = TestClientRegistrations.clientCredentials()
+ .registrationId("client-1").tokenUri(this.serverUrl).build();
+ when(this.clientRegistrationRepository.findByRegistrationId(eq(clientRegistration1.getRegistrationId()))).thenReturn(clientRegistration1);
+
+ // Client 2
+ this.server.enqueue(jsonResponse(accessTokenResponse));
+ this.server.enqueue(jsonResponse(clientResponse));
+
+ ClientRegistration clientRegistration2 = TestClientRegistrations.clientCredentials()
+ .registrationId("client-2").tokenUri(this.serverUrl).build();
+ when(this.clientRegistrationRepository.findByRegistrationId(eq(clientRegistration2.getRegistrationId()))).thenReturn(clientRegistration2);
+
+ this.webClient
+ .get()
+ .uri(this.serverUrl)
+ .attributes(clientRegistrationId(clientRegistration1.getRegistrationId()))
+ .retrieve()
+ .bodyToMono(String.class)
+ .flatMap(response -> this.webClient
+ .get()
+ .uri(this.serverUrl)
+ .attributes(clientRegistrationId(clientRegistration2.getRegistrationId()))
+ .retrieve()
+ .bodyToMono(String.class))
+ .block();
+
+ assertThat(this.server.getRequestCount()).isEqualTo(4);
+
+ ArgumentCaptor authorizedClientCaptor = ArgumentCaptor.forClass(OAuth2AuthorizedClient.class);
+ verify(this.authorizedClientRepository, times(2)).saveAuthorizedClient(
+ authorizedClientCaptor.capture(), eq(this.authentication), eq(this.request), eq(this.response));
+ assertThat(authorizedClientCaptor.getAllValues().get(0).getClientRegistration()).isSameAs(clientRegistration1);
+ assertThat(authorizedClientCaptor.getAllValues().get(1).getClientRegistration()).isSameAs(clientRegistration2);
+ }
+
+ private MockResponse jsonResponse(String json) {
+ return new MockResponse()
+ .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
+ .setBody(json);
+ }
+}
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunctionTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunctionTests.java
index 6b71657f626..8a6dec12955 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunctionTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunctionTests.java
@@ -62,7 +62,10 @@
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.CoreSubscriber;
+import reactor.core.publisher.BaseSubscriber;
import reactor.core.publisher.Mono;
+import reactor.util.context.Context;
import java.net.URI;
import java.time.Duration;
@@ -78,7 +81,11 @@
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.*;
@@ -126,9 +133,10 @@ public void setup() {
}
@After
- public void cleanup() {
+ public void cleanup() throws Exception {
SecurityContextHolder.clearContext();
RequestContextHolder.resetRequestAttributes();
+ this.function.destroy();
}
@Test
@@ -207,7 +215,10 @@ public void defaultRequestOAuth2AuthorizedClientWhenRepositoryNullThenOAuth2Auth
}
@Test
- public void defaultRequestOAuth2AuthorizedClientWhenDefaultTrueAndAuthenticationAndClientRegistrationIdNullThenOAuth2AuthorizedClient() {
+ public void defaultRequestOAuth2AuthorizedClientWhenDefaultTrueAndClientRegistrationIdNullThenOAuth2AuthorizedClient() {
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request, response));
this.function = new ServletOAuth2AuthorizedClientExchangeFilterFunction(this.clientRegistrationRepository,
this.authorizedClientRepository);
this.function.setDefaultOAuth2AuthorizedClient(true);
@@ -241,6 +252,9 @@ public void defaultRequestOAuth2AuthorizedClientWhenDefaultFalseAndAuthenticatio
@Test
public void defaultRequestOAuth2AuthorizedClientWhenAuthenticationAndClientRegistrationIdThenIdIsExplicit() {
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request, response));
this.function = new ServletOAuth2AuthorizedClientExchangeFilterFunction(this.clientRegistrationRepository,
this.authorizedClientRepository);
OAuth2User user = mock(OAuth2User.class);
@@ -259,7 +273,11 @@ public void defaultRequestOAuth2AuthorizedClientWhenAuthenticationAndClientRegis
}
@Test
- public void defaultRequestOAuth2AuthorizedClientWhenAuthenticationNullAndClientRegistrationIdThenOAuth2AuthorizedClient() {
+ public void defaultRequestOAuth2AuthorizedClientWhenClientRegistrationIdThenOAuth2AuthorizedClient() {
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request, response));
+ SecurityContextHolder.getContext().setAuthentication(this.authentication);
this.function = new ServletOAuth2AuthorizedClientExchangeFilterFunction(this.clientRegistrationRepository,
this.authorizedClientRepository);
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration,
@@ -273,63 +291,6 @@ public void defaultRequestOAuth2AuthorizedClientWhenAuthenticationNullAndClientR
verify(this.authorizedClientRepository).loadAuthorizedClient(eq("id"), any(), any());
}
- @Test
- public void defaultRequestWhenClientCredentialsThenAuthorizedClient() {
- this.registration = TestClientRegistrations.clientCredentials().build();
- this.function = new ServletOAuth2AuthorizedClientExchangeFilterFunction(this.clientRegistrationRepository,
- this.authorizedClientRepository);
- this.function.setClientCredentialsTokenResponseClient(this.clientCredentialsTokenResponseClient);
- when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(this.registration);
- OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses
- .accessTokenResponse().build();
- when(this.clientCredentialsTokenResponseClient.getTokenResponse(any())).thenReturn(
- accessTokenResponse);
-
- clientRegistrationId(this.registration.getRegistrationId()).accept(this.result);
-
- Map attrs = getDefaultRequestAttributes();
- OAuth2AuthorizedClient authorizedClient = getOAuth2AuthorizedClient(attrs);
-
- assertThat(authorizedClient.getAccessToken()).isEqualTo(accessTokenResponse.getAccessToken());
- assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration);
- assertThat(authorizedClient.getPrincipalName()).isEqualTo("anonymousUser");
- assertThat(authorizedClient.getRefreshToken()).isEqualTo(accessTokenResponse.getRefreshToken());
- }
-
- @Test
- public void defaultRequestWhenDefaultClientRegistrationIdThenAuthorizedClient() {
- this.registration = TestClientRegistrations.clientCredentials().build();
- this.function = new ServletOAuth2AuthorizedClientExchangeFilterFunction(this.clientRegistrationRepository,
- this.authorizedClientRepository);
- this.function.setDefaultClientRegistrationId(this.registration.getRegistrationId());
- this.function.setClientCredentialsTokenResponseClient(this.clientCredentialsTokenResponseClient);
- when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(this.registration);
- OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses
- .accessTokenResponse().build();
- when(this.clientCredentialsTokenResponseClient.getTokenResponse(any())).thenReturn(
- accessTokenResponse);
-
- Map attrs = getDefaultRequestAttributes();
- OAuth2AuthorizedClient authorizedClient = getOAuth2AuthorizedClient(attrs);
-
- assertThat(authorizedClient.getAccessToken()).isEqualTo(accessTokenResponse.getAccessToken());
- assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration);
- assertThat(authorizedClient.getPrincipalName()).isEqualTo("anonymousUser");
- assertThat(authorizedClient.getRefreshToken()).isEqualTo(accessTokenResponse.getRefreshToken());
- }
-
- @Test
- public void defaultRequestWhenClientIdNotFoundThenIllegalArgumentException() {
- this.registration = TestClientRegistrations.clientCredentials().build();
- this.function = new ServletOAuth2AuthorizedClientExchangeFilterFunction(this.clientRegistrationRepository,
- this.authorizedClientRepository);
-
- clientRegistrationId(this.registration.getRegistrationId()).accept(this.result);
-
- assertThatCode(() -> getDefaultRequestAttributes())
- .isInstanceOf(IllegalArgumentException.class);
- }
-
private Map getDefaultRequestAttributes() {
this.function.defaultRequest().accept(this.spec);
verify(this.spec).attributes(this.attrs.capture());
@@ -477,6 +438,80 @@ public void filterWhenRefreshRequiredThenRefreshAndResponseDoesNotContainRefresh
assertThat(getBody(request1)).isEmpty();
}
+ @Test
+ public void filterWhenClientCredentialsTokenNotExpiredThenUseCurrentToken() {
+ this.registration = TestClientRegistrations.clientCredentials().build();
+
+ this.function = new ServletOAuth2AuthorizedClientExchangeFilterFunction(this.clientRegistrationRepository,
+ this.authorizedClientRepository);
+ this.function.setClientCredentialsTokenResponseClient(this.clientCredentialsTokenResponseClient);
+
+ OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration,
+ "principalName", this.accessToken, null);
+ ClientRequest request = ClientRequest.create(GET, URI.create("https://example.com"))
+ .attributes(oauth2AuthorizedClient(authorizedClient))
+ .attributes(authentication(this.authentication))
+ .build();
+
+ this.function.filter(request, this.exchange).block();
+
+ verify(this.authorizedClientRepository, never()).saveAuthorizedClient(any(), eq(this.authentication), any(), any());
+
+ verify(clientCredentialsTokenResponseClient, never()).getTokenResponse(any());
+
+ List requests = this.exchange.getRequests();
+ assertThat(requests).hasSize(1);
+
+ ClientRequest request1 = requests.get(0);
+ assertThat(request1.headers().getFirst(HttpHeaders.AUTHORIZATION)).isEqualTo("Bearer token-0");
+ assertThat(request1.url().toASCIIString()).isEqualTo("https://example.com");
+ assertThat(request1.method()).isEqualTo(HttpMethod.GET);
+ assertThat(getBody(request1)).isEmpty();
+ }
+
+ @Test
+ public void filterWhenClientCredentialsTokenExpiredThenGetNewToken() {
+ this.registration = TestClientRegistrations.clientCredentials().build();
+
+ OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses
+ .accessTokenResponse().build();
+ when(this.clientCredentialsTokenResponseClient.getTokenResponse(any())).thenReturn(
+ accessTokenResponse);
+
+ Instant issuedAt = Instant.now().minus(Duration.ofDays(1));
+ Instant accessTokenExpiresAt = issuedAt.plus(Duration.ofHours(1));
+
+ this.accessToken = new OAuth2AccessToken(this.accessToken.getTokenType(),
+ this.accessToken.getTokenValue(),
+ issuedAt,
+ accessTokenExpiresAt);
+ this.function = new ServletOAuth2AuthorizedClientExchangeFilterFunction(this.clientRegistrationRepository,
+ this.authorizedClientRepository);
+ this.function.setClientCredentialsTokenResponseClient(this.clientCredentialsTokenResponseClient);
+
+ OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration,
+ "principalName", this.accessToken, null);
+ ClientRequest request = ClientRequest.create(GET, URI.create("https://example.com"))
+ .attributes(oauth2AuthorizedClient(authorizedClient))
+ .attributes(authentication(this.authentication))
+ .build();
+
+ this.function.filter(request, this.exchange).block();
+
+ verify(this.authorizedClientRepository).saveAuthorizedClient(any(), eq(this.authentication), any(), any());
+
+ verify(clientCredentialsTokenResponseClient).getTokenResponse(any());
+
+ List requests = this.exchange.getRequests();
+ assertThat(requests).hasSize(1);
+
+ ClientRequest request1 = requests.get(0);
+ assertThat(request1.headers().getFirst(HttpHeaders.AUTHORIZATION)).isEqualTo("Bearer token");
+ assertThat(request1.url().toASCIIString()).isEqualTo("https://example.com");
+ assertThat(request1.method()).isEqualTo(HttpMethod.GET);
+ assertThat(getBody(request1)).isEmpty();
+ }
+
@Test
public void filterWhenRefreshRequiredAndEmptyReactiveSecurityContextThenSaved() {
OAuth2AccessTokenResponse response = OAuth2AccessTokenResponse.withToken("token-1")
@@ -685,6 +720,90 @@ public void filterWhenRequestAttributesNotSetAndHooksInitHooksResetThenDefaultsN
assertThat(getBody(request)).isEmpty();
}
+ // gh-7228
+ @Test
+ public void afterPropertiesSetWhenHooksInitAndOutsideWebSecurityContextThenShouldNotThrowException() throws Exception {
+ this.function.afterPropertiesSet(); // Hooks.onLastOperator() initialized
+ assertThatCode(() -> Mono.subscriberContext().block())
+ .as("RequestContext Hook brakes application outside of web/security context")
+ .doesNotThrowAnyException();
+ }
+
+ @Test
+ public void createRequestContextSubscriberIfNecessaryWhenOutsideWebSecurityContextThenReturnOriginalSubscriber() throws Exception {
+ BaseSubscriber originalSubscriber = new BaseSubscriber() {};
+ CoreSubscriber resultSubscriber = this.function.createRequestContextSubscriberIfNecessary(originalSubscriber);
+ assertThat(resultSubscriber).isSameAs(originalSubscriber);
+ }
+
+ // gh-7228
+ @Test
+ public void createRequestContextSubscriberWhenRequestResponseProvidedThenCreateWithParentContext() throws Exception {
+ testRequestContextSubscriber(new MockHttpServletRequest(), new MockHttpServletResponse(), null);
+ }
+
+ // gh-7228
+ @Test
+ public void createRequestContextSubscriberWhenAuthenticationProvidedThenCreateWithParentContext() throws Exception {
+ testRequestContextSubscriber(null, null, this.authentication);
+ }
+
+ @Test
+ public void createRequestContextSubscriberWhenParentContextHasDataHolderThenShouldReuseParentContext() throws Exception {
+ RequestContextDataHolder testValue = new RequestContextDataHolder(null, null, null);
+ final Context parentContext = Context.of(RequestContextSubscriber.REQUEST_CONTEXT_DATA_HOLDER, testValue);
+ BaseSubscriber parent = new BaseSubscriber() {
+ @Override
+ public Context currentContext() {
+ return parentContext;
+ }
+ };
+
+ RequestContextSubscriber requestContextSubscriber =
+ new RequestContextSubscriber<>(parent, null, null, authentication);
+
+ Context resultContext = requestContextSubscriber.currentContext();
+
+ assertThat(resultContext)
+ .describedAs("parent context was replaced")
+ .isSameAs(parentContext);
+ }
+
+ private void testRequestContextSubscriber(MockHttpServletRequest servletRequest,
+ MockHttpServletResponse servletResponse,
+ Authentication authentication) {
+ String testKey = "test_key";
+ String testValue = "test_value";
+
+ BaseSubscriber parent = new BaseSubscriber() {
+ @Override
+ public Context currentContext() {
+ return Context.of(testKey, testValue);
+ }
+ };
+
+ RequestContextSubscriber requestContextSubscriber =
+ new RequestContextSubscriber<>(parent, servletRequest, servletResponse, authentication);
+
+ Context resultContext = requestContextSubscriber.currentContext();
+
+ assertThat(resultContext)
+ .describedAs("result context is null")
+ .isNotNull();
+
+ assertThat(resultContext.getOrEmpty(testKey))
+ .describedAs("context is replaced")
+ .hasValue(testValue);
+
+ Object dataHolder = resultContext.getOrDefault(RequestContextSubscriber.REQUEST_CONTEXT_DATA_HOLDER, null);
+ assertThat(dataHolder)
+ .describedAs("context is not populated with REQUEST_CONTEXT_DATA_HOLDER")
+ .isNotNull()
+ .hasFieldOrPropertyWithValue("request", servletRequest)
+ .hasFieldOrPropertyWithValue("response", servletResponse)
+ .hasFieldOrPropertyWithValue("authentication", authentication);
+ }
+
private static String getBody(ClientRequest request) {
final List> messageWriters = new ArrayList<>();
messageWriters.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolverTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolverTests.java
index 170b57620e9..21f98fcd471 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolverTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/DefaultServerOAuth2AuthorizationRequestResolverTests.java
@@ -87,4 +87,18 @@ private OAuth2AuthorizationRequest resolve(String path) {
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(path));
return this.resolver.resolve(exchange).block();
}
+
+ @Test
+ public void resolveWhenForwardedHeadersClientRegistrationFoundThenWorks() {
+ when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(
+ Mono.just(this.registration));
+ ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/oauth2/authorization/id").header("X-Forwarded-Host", "evil.com"));
+
+ OAuth2AuthorizationRequest request = this.resolver.resolve(exchange).block();
+
+ assertThat(request.getAuthorizationRequestUri()).matches("https://example.com/login/oauth/authorize\\?" +
+ "response_type=code&client_id=client-id&" +
+ "scope=read:user&state=.*?&" +
+ "redirect_uri=/login/oauth2/code/registration-id");
+ }
}
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationCodeGrantWebFilterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationCodeGrantWebFilterTests.java
index 5727a26fa34..cbc08accd63 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationCodeGrantWebFilterTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/OAuth2AuthorizationCodeGrantWebFilterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -25,19 +25,28 @@
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.TestOAuth2AuthorizationCodeAuthenticationTokens;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
-import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
+import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
+import org.springframework.util.CollectionUtils;
import org.springframework.web.server.handler.DefaultWebFilterChain;
import reactor.core.publisher.Mono;
-import static org.assertj.core.api.Assertions.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import static org.springframework.security.oauth2.core.endpoint.TestOAuth2AuthorizationRequests.request;
/**
* @author Rob Winch
@@ -53,6 +62,9 @@ public class OAuth2AuthorizationCodeGrantWebFilterTests {
@Mock
private ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
+ private ServerAuthorizationRequestRepository authorizationRequestRepository =
+ new WebSessionOAuth2ServerAuthorizationRequestRepository();
+
@Before
public void setup() {
this.filter = new OAuth2AuthorizationCodeGrantWebFilter(
@@ -92,7 +104,7 @@ public void filterWhenNotMatchThenAuthenticationManagerNotCalled() {
MockServerWebExchange exchange = MockServerWebExchange
.from(MockServerHttpRequest.get("/"));
DefaultWebFilterChain chain = new DefaultWebFilterChain(
- e -> e.getResponse().setComplete());
+ e -> e.getResponse().setComplete(), Collections.emptyList());
this.filter.filter(exchange, chain).block();
@@ -101,25 +113,154 @@ public void filterWhenNotMatchThenAuthenticationManagerNotCalled() {
@Test
public void filterWhenMatchThenAuthorizedClientSaved() {
- Mono authentication = Mono
- .just(TestOAuth2AuthorizationCodeAuthenticationTokens.unauthenticated());
- OAuth2AuthorizationCodeAuthenticationToken authenticated = TestOAuth2AuthorizationCodeAuthenticationTokens
- .authenticated();
- ServerAuthenticationConverter converter = e -> authentication;
- this.filter = new OAuth2AuthorizationCodeGrantWebFilter(
- this.authenticationManager, converter, this.authorizedClientRepository);
- MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest
- .get("/authorize/oauth2/code/registration-id"));
- DefaultWebFilterChain chain = new DefaultWebFilterChain(
- e -> e.getResponse().setComplete());
- when(this.authenticationManager.authenticate(any())).thenReturn(Mono.just(
- authenticated));
+ ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
+ when(this.clientRegistrationRepository.findByRegistrationId(any()))
+ .thenReturn(Mono.just(clientRegistration));
when(this.authorizedClientRepository.saveAuthorizedClient(any(), any(), any()))
.thenReturn(Mono.empty());
+ when(this.authenticationManager.authenticate(any()))
+ .thenReturn(Mono.just(TestOAuth2AuthorizationCodeAuthenticationTokens.authenticated()));
+
+ MockServerHttpRequest authorizationRequest =
+ createAuthorizationRequest("/authorization/callback");
+ OAuth2AuthorizationRequest oauth2AuthorizationRequest =
+ createOAuth2AuthorizationRequest(authorizationRequest, clientRegistration);
+ MockServerHttpRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
+ MockServerWebExchange exchange = MockServerWebExchange.from(authorizationResponse);
+ this.authorizationRequestRepository.saveAuthorizationRequest(oauth2AuthorizationRequest, exchange).block();
+ DefaultWebFilterChain chain = new DefaultWebFilterChain(
+ e -> e.getResponse().setComplete(), Collections.emptyList());
this.filter.filter(exchange, chain).block();
verify(this.authorizedClientRepository).saveAuthorizedClient(any(), any(AnonymousAuthenticationToken.class), any());
+ }
+
+ // gh-7966
+ @Test
+ public void filterWhenAuthorizationRequestRedirectUriParametersMatchThenProcessed() {
+ ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
+ when(this.clientRegistrationRepository.findByRegistrationId(any()))
+ .thenReturn(Mono.just(clientRegistration));
+ when(this.authorizedClientRepository.saveAuthorizedClient(any(), any(), any()))
+ .thenReturn(Mono.empty());
+ when(this.authenticationManager.authenticate(any()))
+ .thenReturn(Mono.just(TestOAuth2AuthorizationCodeAuthenticationTokens.authenticated()));
+
+ // 1) redirect_uri with query parameters
+ Map parameters = new LinkedHashMap<>();
+ parameters.put("param1", "value1");
+ parameters.put("param2", "value2");
+ MockServerHttpRequest authorizationRequest =
+ createAuthorizationRequest("/authorization/callback", parameters);
+ OAuth2AuthorizationRequest oauth2AuthorizationRequest =
+ createOAuth2AuthorizationRequest(authorizationRequest, clientRegistration);
+ MockServerHttpRequest authorizationResponse = createAuthorizationResponse(authorizationRequest);
+ MockServerWebExchange exchange = MockServerWebExchange.from(authorizationResponse);
+ this.authorizationRequestRepository.saveAuthorizationRequest(oauth2AuthorizationRequest, exchange).block();
+ DefaultWebFilterChain chain = new DefaultWebFilterChain(
+ e -> e.getResponse().setComplete(), Collections.emptyList());
+
+ this.filter.filter(exchange, chain).block();
+ verify(this.authenticationManager, times(1)).authenticate(any());
+
+ // 2) redirect_uri with query parameters AND authorization response additional parameters
+ Map additionalParameters = new LinkedHashMap<>();
+ additionalParameters.put("auth-param1", "value1");
+ additionalParameters.put("auth-param2", "value2");
+ authorizationResponse = createAuthorizationResponse(authorizationRequest, additionalParameters);
+ exchange = MockServerWebExchange.from(authorizationResponse);
+ this.authorizationRequestRepository.saveAuthorizationRequest(oauth2AuthorizationRequest, exchange).block();
+
+ this.filter.filter(exchange, chain).block();
+ verify(this.authenticationManager, times(2)).authenticate(any());
+ }
+
+ // gh-7966
+ @Test
+ public void filterWhenAuthorizationRequestRedirectUriParametersNotMatchThenNotProcessed() {
+ String requestUri = "/authorization/callback";
+ Map parameters = new LinkedHashMap<>();
+ parameters.put("param1", "value1");
+ parameters.put("param2", "value2");
+ MockServerHttpRequest authorizationRequest =
+ createAuthorizationRequest(requestUri, parameters);
+ ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration().build();
+ OAuth2AuthorizationRequest oauth2AuthorizationRequest =
+ createOAuth2AuthorizationRequest(authorizationRequest, clientRegistration);
+
+ // 1) Parameter value
+ Map parametersNotMatch = new LinkedHashMap<>(parameters);
+ parametersNotMatch.put("param2", "value8");
+ MockServerHttpRequest authorizationResponse = createAuthorizationResponse(
+ createAuthorizationRequest(requestUri, parametersNotMatch));
+ MockServerWebExchange exchange = MockServerWebExchange.from(authorizationResponse);
+ this.authorizationRequestRepository.saveAuthorizationRequest(oauth2AuthorizationRequest, exchange).block();
+ DefaultWebFilterChain chain = new DefaultWebFilterChain(
+ e -> e.getResponse().setComplete(), Collections.emptyList());
+
+ this.filter.filter(exchange, chain).block();
+ verifyZeroInteractions(this.authenticationManager);
+
+ // 2) Parameter order
+ parametersNotMatch = new LinkedHashMap<>();
+ parametersNotMatch.put("param2", "value2");
+ parametersNotMatch.put("param1", "value1");
+ authorizationResponse = createAuthorizationResponse(
+ createAuthorizationRequest(requestUri, parametersNotMatch));
+ exchange = MockServerWebExchange.from(authorizationResponse);
+ this.authorizationRequestRepository.saveAuthorizationRequest(oauth2AuthorizationRequest, exchange).block();
+
+ this.filter.filter(exchange, chain).block();
+ verifyZeroInteractions(this.authenticationManager);
+
+ // 3) Parameter missing
+ parametersNotMatch = new LinkedHashMap<>(parameters);
+ parametersNotMatch.remove("param2");
+ authorizationResponse = createAuthorizationResponse(
+ createAuthorizationRequest(requestUri, parametersNotMatch));
+ exchange = MockServerWebExchange.from(authorizationResponse);
+ this.authorizationRequestRepository.saveAuthorizationRequest(oauth2AuthorizationRequest, exchange).block();
+
+ this.filter.filter(exchange, chain).block();
+ verifyZeroInteractions(this.authenticationManager);
+ }
+
+ private static OAuth2AuthorizationRequest createOAuth2AuthorizationRequest(
+ MockServerHttpRequest authorizationRequest, ClientRegistration registration) {
+ Map additionalParameters = new HashMap<>();
+ additionalParameters.put(OAuth2ParameterNames.REGISTRATION_ID, registration.getRegistrationId());
+ return request()
+ .additionalParameters(additionalParameters)
+ .redirectUri(authorizationRequest.getURI().toString())
+ .build();
+ }
+
+ private static MockServerHttpRequest createAuthorizationRequest(String requestUri) {
+ return createAuthorizationRequest(requestUri, new LinkedHashMap<>());
+ }
+
+ private static MockServerHttpRequest createAuthorizationRequest(String requestUri, Map parameters) {
+ MockServerHttpRequest.BaseBuilder> builder = MockServerHttpRequest
+ .get(requestUri);
+ if (!CollectionUtils.isEmpty(parameters)) {
+ parameters.forEach(builder::queryParam);
+ }
+ return builder.build();
+ }
+
+ private static MockServerHttpRequest createAuthorizationResponse(MockServerHttpRequest authorizationRequest) {
+ return createAuthorizationResponse(authorizationRequest, new LinkedHashMap<>());
+ }
+ private static MockServerHttpRequest createAuthorizationResponse(
+ MockServerHttpRequest authorizationRequest, Map additionalParameters) {
+ MockServerHttpRequest.BaseBuilder> builder = MockServerHttpRequest
+ .get(authorizationRequest.getURI().toString());
+ builder.queryParam(OAuth2ParameterNames.CODE, "code");
+ builder.queryParam(OAuth2ParameterNames.STATE, "state");
+ additionalParameters.forEach(builder::queryParam);
+ builder.cookies(authorizationRequest.getCookies());
+ return builder.build();
}
}
diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/WebSessionOAuth2ServerAuthorizationRequestRepositoryTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/WebSessionOAuth2ServerAuthorizationRequestRepositoryTests.java
index 79d17eabd1b..b4e11c05be4 100644
--- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/WebSessionOAuth2ServerAuthorizationRequestRepositoryTests.java
+++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/server/WebSessionOAuth2ServerAuthorizationRequestRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,7 +63,7 @@ public class WebSessionOAuth2ServerAuthorizationRequestRepositoryTests {
.queryParam(OAuth2ParameterNames.STATE, "state"));
@Test
- public void loadAuthorizatioNRequestWhenNullExchangeThenIllegalArgumentException() {
+ public void loadAuthorizationRequestWhenNullExchangeThenIllegalArgumentException() {
this.exchange = null;
assertThatThrownBy(() -> this.repository.loadAuthorizationRequest(this.exchange))
.isInstanceOf(IllegalArgumentException.class);
@@ -106,36 +106,6 @@ public void loadAuthorizationRequestWhenSavedThenAuthorizationRequest() {
.verifyComplete();
}
- @Test
- public void multipleSavedAuthorizationRequestAndRedisCookie() {
- String oldState = "state0";
- MockServerHttpRequest oldRequest = MockServerHttpRequest.get("/")
- .queryParam(OAuth2ParameterNames.STATE, oldState).build();
-
- OAuth2AuthorizationRequest oldAuthorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
- .authorizationUri("https://example.com/oauth2/authorize")
- .clientId("client-id")
- .redirectUri("http://localhost/client-1")
- .state(oldState)
- .build();
-
- Map sessionAttrs = spy(new HashMap<>());
- WebSession session = mock(WebSession.class);
- when(session.getAttributes()).thenReturn(sessionAttrs);
- WebSessionManager sessionManager = e -> Mono.just(session);
-
- this.exchange = new DefaultServerWebExchange(this.exchange.getRequest(), new MockServerHttpResponse(), sessionManager,
- ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
- ServerWebExchange oldExchange = new DefaultServerWebExchange(oldRequest, new MockServerHttpResponse(), sessionManager,
- ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
-
- Mono saveAndSave = this.repository.saveAuthorizationRequest(oldAuthorizationRequest, oldExchange)
- .then(this.repository.saveAuthorizationRequest(this.authorizationRequest, this.exchange));
-
- StepVerifier.create(saveAndSave).verifyComplete();
- verify(sessionAttrs, times(2)).put(any(), any());
- }
-
@Test
public void loadAuthorizationRequestWhenMultipleSavedThenAuthorizationRequest() {
String oldState = "state0";
@@ -269,6 +239,44 @@ public void removeAuthorizationRequestWhenMultipleThenOnlyOneRemoved() {
.verifyComplete();
}
+ // gh-7327
+ @Test
+ public void removeAuthorizationRequestWhenMultipleThenRemovedAndSessionAttributeUpdated() {
+ String oldState = "state0";
+ MockServerHttpRequest oldRequest = MockServerHttpRequest.get("/")
+ .queryParam(OAuth2ParameterNames.STATE, oldState).build();
+
+ OAuth2AuthorizationRequest oldAuthorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
+ .authorizationUri("https://example.com/oauth2/authorize")
+ .clientId("client-id")
+ .redirectUri("http://localhost/client-1")
+ .state(oldState)
+ .build();
+
+ Map sessionAttrs = spy(new HashMap<>());
+ WebSession session = mock(WebSession.class);
+ when(session.getAttributes()).thenReturn(sessionAttrs);
+ WebSessionManager sessionManager = e -> Mono.just(session);
+
+ this.exchange = new DefaultServerWebExchange(this.exchange.getRequest(), new MockServerHttpResponse(), sessionManager,
+ ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
+ ServerWebExchange oldExchange = new DefaultServerWebExchange(oldRequest, new MockServerHttpResponse(), sessionManager,
+ ServerCodecConfigurer.create(), new AcceptHeaderLocaleContextResolver());
+
+ Mono saveAndSaveAndRemove = this.repository.saveAuthorizationRequest(oldAuthorizationRequest, oldExchange)
+ .then(this.repository.saveAuthorizationRequest(this.authorizationRequest, this.exchange))
+ .then(this.repository.removeAuthorizationRequest(this.exchange));
+
+ StepVerifier.create(saveAndSaveAndRemove)
+ .expectNext(this.authorizationRequest)
+ .verifyComplete();
+
+ StepVerifier.create(this.repository.loadAuthorizationRequest(this.exchange))
+ .verifyComplete();
+
+ verify(sessionAttrs, times(3)).put(any(), any());
+ }
+
private void assertSessionStartedIs(boolean expected) {
Mono isStarted = this.exchange.getSession().map(WebSession::isStarted);
StepVerifier.create(isStarted)
diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverter.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverter.java
index 75a6718ba3a..115e36260b1 100644
--- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverter.java
+++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -57,8 +57,8 @@
public class OAuth2AccessTokenResponseHttpMessageConverter extends AbstractHttpMessageConverter {
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
- private static final ParameterizedTypeReference> PARAMETERIZED_RESPONSE_TYPE =
- new ParameterizedTypeReference>() {};
+ private static final ParameterizedTypeReference> PARAMETERIZED_RESPONSE_TYPE =
+ new ParameterizedTypeReference>() {};
private GenericHttpMessageConverter jsonMessageConverter = HttpMessageConverters.getJsonMessageConverter();
@@ -82,10 +82,16 @@ protected OAuth2AccessTokenResponse readInternal(Class extends OAuth2AccessTok
throws IOException, HttpMessageNotReadableException {
try {
+ // gh-6463
+ // Parse parameter values as Object in order to handle potential JSON Object and then convert values to String
@SuppressWarnings("unchecked")
- Map tokenResponseParameters = (Map) this.jsonMessageConverter.read(
+ Map tokenResponseParameters = (Map) this.jsonMessageConverter.read(
PARAMETERIZED_RESPONSE_TYPE.getType(), null, inputMessage);
- return this.tokenResponseConverter.convert(tokenResponseParameters);
+ return this.tokenResponseConverter.convert(
+ tokenResponseParameters.entrySet().stream()
+ .collect(Collectors.toMap(
+ Map.Entry::getKey,
+ entry -> entry.getValue().toString())));
} catch (Exception ex) {
throw new HttpMessageNotReadableException("An error occurred reading the OAuth 2.0 Access Token Response: " +
ex.getMessage(), ex, inputMessage);
diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2ErrorHttpMessageConverter.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2ErrorHttpMessageConverter.java
index b5f192b0d74..89ad73730e1 100644
--- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2ErrorHttpMessageConverter.java
+++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/http/converter/OAuth2ErrorHttpMessageConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -35,6 +35,7 @@
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
+import java.util.stream.Collectors;
/**
* A {@link HttpMessageConverter} for an {@link OAuth2Error OAuth 2.0 Error}.
@@ -47,8 +48,8 @@
public class OAuth2ErrorHttpMessageConverter extends AbstractHttpMessageConverter {
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
- private static final ParameterizedTypeReference> PARAMETERIZED_RESPONSE_TYPE =
- new ParameterizedTypeReference>() {};
+ private static final ParameterizedTypeReference> PARAMETERIZED_RESPONSE_TYPE =
+ new ParameterizedTypeReference>() {};
private GenericHttpMessageConverter jsonMessageConverter = HttpMessageConverters.getJsonMessageConverter();
@@ -70,10 +71,16 @@ protected OAuth2Error readInternal(Class extends OAuth2Error> clazz, HttpInput
throws IOException, HttpMessageNotReadableException {
try {
+ // gh-8157
+ // Parse parameter values as Object in order to handle potential JSON Object and then convert values to String
@SuppressWarnings("unchecked")
- Map errorParameters = (Map) this.jsonMessageConverter.read(
+ Map errorParameters = (Map) this.jsonMessageConverter.read(
PARAMETERIZED_RESPONSE_TYPE.getType(), null, inputMessage);
- return this.errorConverter.convert(errorParameters);
+ return this.errorConverter.convert(
+ errorParameters.entrySet().stream()
+ .collect(Collectors.toMap(
+ Map.Entry::getKey,
+ entry -> String.valueOf(entry.getValue()))));
} catch (Exception ex) {
throw new HttpMessageNotReadableException("An error occurred reading the OAuth 2.0 Error: " +
ex.getMessage(), ex, inputMessage);
diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverterTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverterTests.java
index bf74c947303..e96e85d1098 100644
--- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverterTests.java
+++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2AccessTokenResponseHttpMessageConverterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -96,6 +96,39 @@ public void readInternalWhenSuccessfulTokenResponseThenReadOAuth2AccessTokenResp
}
+ // gh-6463
+ @Test
+ public void readInternalWhenSuccessfulTokenResponseWithObjectThenReadOAuth2AccessTokenResponse() throws Exception {
+ String tokenResponse = "{\n" +
+ " \"access_token\": \"access-token-1234\",\n" +
+ " \"token_type\": \"bearer\",\n" +
+ " \"expires_in\": 3600,\n" +
+ " \"scope\": \"read write\",\n" +
+ " \"refresh_token\": \"refresh-token-1234\",\n" +
+ " \"custom_object_1\": {\"name1\": \"value1\"},\n" +
+ " \"custom_object_2\": [\"value1\", \"value2\"],\n" +
+ " \"custom_parameter_1\": \"custom-value-1\",\n" +
+ " \"custom_parameter_2\": \"custom-value-2\"\n" +
+ "}\n";
+
+ MockClientHttpResponse response = new MockClientHttpResponse(
+ tokenResponse.getBytes(), HttpStatus.OK);
+
+ OAuth2AccessTokenResponse accessTokenResponse = this.messageConverter.readInternal(
+ OAuth2AccessTokenResponse.class, response);
+
+ assertThat(accessTokenResponse.getAccessToken().getTokenValue()).isEqualTo("access-token-1234");
+ assertThat(accessTokenResponse.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER);
+ assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBeforeOrEqualTo(Instant.now().plusSeconds(3600));
+ assertThat(accessTokenResponse.getAccessToken().getScopes()).containsExactly("read", "write");
+ assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo("refresh-token-1234");
+ assertThat(accessTokenResponse.getAdditionalParameters()).containsExactly(
+ entry("custom_object_1", "{name1=value1}"),
+ entry("custom_object_2", "[value1, value2]"),
+ entry("custom_parameter_1", "custom-value-1"),
+ entry("custom_parameter_2", "custom-value-2"));
+ }
+
@Test
public void readInternalWhenConversionFailsThenThrowHttpMessageNotReadableException() {
Converter tokenResponseConverter = mock(Converter.class);
diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2ErrorHttpMessageConverterTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2ErrorHttpMessageConverterTests.java
index a57b1df1b83..11211aad561 100644
--- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2ErrorHttpMessageConverterTests.java
+++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/http/converter/OAuth2ErrorHttpMessageConverterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -78,6 +78,25 @@ public void readInternalWhenErrorResponseThenReadOAuth2Error() throws Exception
assertThat(oauth2Error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6749#section-5.2");
}
+ // gh-8157
+ @Test
+ public void readInternalWhenErrorResponseWithObjectThenReadOAuth2Error() throws Exception {
+ String errorResponse = "{\n" +
+ " \"error\": \"unauthorized_client\",\n" +
+ " \"error_description\": \"The client is not authorized\",\n" +
+ " \"error_codes\": [65001],\n" +
+ " \"error_uri\": \"https://tools.ietf.org/html/rfc6749#section-5.2\"\n" +
+ "}\n";
+
+ MockClientHttpResponse response = new MockClientHttpResponse(
+ errorResponse.getBytes(), HttpStatus.BAD_REQUEST);
+
+ OAuth2Error oauth2Error = this.messageConverter.readInternal(OAuth2Error.class, response);
+ assertThat(oauth2Error.getErrorCode()).isEqualTo("unauthorized_client");
+ assertThat(oauth2Error.getDescription()).isEqualTo("The client is not authorized");
+ assertThat(oauth2Error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6749#section-5.2");
+ }
+
@Test
public void readInternalWhenConversionFailsThenThrowHttpMessageNotReadableException() {
Converter errorConverter = mock(Converter.class);
diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupport.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupport.java
index 26a39a48666..54d4754fea7 100644
--- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupport.java
+++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupport.java
@@ -20,6 +20,7 @@
import java.net.URL;
import java.text.ParseException;
import java.time.Instant;
+import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -210,12 +211,13 @@ public final void setRestOperations(RestOperations restOperations) {
}
private static class RestOperationsResourceRetriever implements ResourceRetriever {
+ private static final MediaType APPLICATION_JWK_SET_JSON = new MediaType("application", "jwk-set+json");
private RestOperations restOperations = new RestTemplate();
@Override
public Resource retrieveResource(URL url) throws IOException {
HttpHeaders headers = new HttpHeaders();
- headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON_UTF8));
+ headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON, APPLICATION_JWK_SET_JSON));
ResponseEntity response;
try {
diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupportTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupportTests.java
index 5307471f283..ca1e9d75618 100644
--- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupportTests.java
+++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderJwkSupportTests.java
@@ -17,6 +17,7 @@
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import com.nimbusds.jose.JWSAlgorithm;
@@ -31,16 +32,21 @@
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.core.convert.converter.Converter;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
+import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
@@ -76,6 +82,8 @@ public class NimbusJwtDecoderJwkSupportTests {
private static final String MALFORMED_JWT = "eyJhbGciOiJSUzI1NiJ9.eyJuYmYiOnt9LCJleHAiOjQ2ODQyMjUwODd9.guoQvujdWvd3xw7FYQEn4D6-gzM_WqFvXdmvAUNSLbxG7fv2_LLCNujPdrBHJoYPbOwS1BGNxIKQWS1tylvqzmr1RohQ-RZ2iAM1HYQzboUlkoMkcd8ENM__ELqho8aNYBfqwkNdUOyBFoy7Syu_w2SoJADw2RTjnesKO6CVVa05bW118pDS4xWxqC4s7fnBjmZoTn4uQ-Kt9YSQZQk8YQxkJSiyanozzgyfgXULA6mPu1pTNU3FVFaK1i1av_xtH_zAPgb647ZeaNe4nahgqC5h8nhOlm8W2dndXbwAt29nd2ZWBsru_QwZz83XSKLhTPFz-mPBByZZDsyBbIHf9A";
private static final String UNSIGNED_JWT = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJleHAiOi0yMDMzMjI0OTcsImp0aSI6IjEyMyIsInR5cCI6IkpXVCJ9.";
+ private static final MediaType APPLICATION_JWK_SET_JSON = new MediaType("application", "jwk-set+json");
+
private NimbusJwtDecoderJwkSupport jwtDecoder = new NimbusJwtDecoderJwkSupport(JWK_SET_URL, JWS_ALGORITHM);
@Test
@@ -256,4 +264,19 @@ public void setClaimSetConverterWhenIsNullThenThrowsIllegalArgumentException() {
assertThatCode(() -> jwtDecoder.setClaimSetConverter(null))
.isInstanceOf(IllegalArgumentException.class);
}
+
+ // gh-7290
+ @Test
+ public void decodeWhenJwkSetRequestedThenAcceptHeaderJsonAndJwkSetJson() {
+ RestOperations restOperations = mock(RestOperations.class);
+ when(restOperations.exchange(any(RequestEntity.class), eq(String.class)))
+ .thenReturn(new ResponseEntity<>(JWK_SET, HttpStatus.OK));
+ NimbusJwtDecoderJwkSupport jwtDecoder = new NimbusJwtDecoderJwkSupport(JWK_SET_URL);
+ jwtDecoder.setRestOperations(restOperations);
+ jwtDecoder.decode(SIGNED_JWT);
+ ArgumentCaptor requestEntityCaptor = ArgumentCaptor.forClass(RequestEntity.class);
+ verify(restOperations).exchange(requestEntityCaptor.capture(), eq(String.class));
+ List acceptHeader = requestEntityCaptor.getValue().getHeaders().getAccept();
+ assertThat(acceptHeader).contains(MediaType.APPLICATION_JSON, APPLICATION_JWK_SET_JSON);
+ }
}
diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java
index 068077aa2cb..8908360f196 100644
--- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java
+++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java
@@ -48,8 +48,14 @@ public class ServerBearerTokenAuthenticationConverter
private boolean allowUriQueryParameter = false;
public Mono convert(ServerWebExchange exchange) {
- return Mono.justOrEmpty(this.token(exchange.getRequest()))
- .map(BearerTokenAuthenticationToken::new);
+ return Mono.justOrEmpty(token(exchange.getRequest()))
+ .map(token -> {
+ if (token.isEmpty()) {
+ BearerTokenError error = invalidTokenError();
+ throw new OAuth2AuthenticationException(error);
+ }
+ return new BearerTokenAuthenticationToken(token);
+ });
}
private String token(ServerHttpRequest request) {
@@ -88,11 +94,8 @@ private static String resolveFromAuthorizationHeader(HttpHeaders headers) {
if (StringUtils.hasText(authorization) && authorization.startsWith("Bearer")) {
Matcher matcher = authorizationPattern.matcher(authorization);
- if ( !matcher.matches() ) {
- BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN,
- HttpStatus.BAD_REQUEST,
- "Bearer token is malformed",
- "https://tools.ietf.org/html/rfc6750#section-3.1");
+ if (!matcher.matches() ) {
+ BearerTokenError error = invalidTokenError();
throw new OAuth2AuthenticationException(error);
}
@@ -101,6 +104,13 @@ private static String resolveFromAuthorizationHeader(HttpHeaders headers) {
return null;
}
+ private static BearerTokenError invalidTokenError() {
+ return new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN,
+ HttpStatus.UNAUTHORIZED,
+ "Bearer token is malformed",
+ "https://tools.ietf.org/html/rfc6750#section-3.1");
+ }
+
private boolean isParameterTokenSupportedForRequest(ServerHttpRequest request) {
return this.allowUriQueryParameter && HttpMethod.GET.equals(request.getMethod());
}
diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java
index 5a08ee85c9f..a1a88255aac 100644
--- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java
+++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java
@@ -19,15 +19,19 @@
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.BearerTokenError;
+import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes;
import java.util.Base64;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.catchThrowableOfType;
/**
* @author Rob Winch
@@ -52,6 +56,21 @@ public void resolveWhenValidHeaderIsPresentThenTokenIsResolved() {
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
}
+ // gh-7011
+ @Test
+ public void resolveWhenValidHeaderIsEmptyStringThenTokenIsResolved() {
+ MockServerHttpRequest.BaseBuilder> request = MockServerHttpRequest
+ .get("/")
+ .header(HttpHeaders.AUTHORIZATION, "Bearer ");
+
+ OAuth2AuthenticationException expected = catchThrowableOfType(() -> convertToToken(request),
+ OAuth2AuthenticationException.class);
+ BearerTokenError error = (BearerTokenError) expected.getError();
+ assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
+ assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
+ assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
+ }
+
@Test
public void resolveWhenNoHeaderIsPresentThenTokenIsNotResolved() {
MockServerHttpRequest.BaseBuilder> request = MockServerHttpRequest
@@ -114,6 +133,23 @@ public void resolveWhenQueryParameterIsPresentAndSupportedThenTokenIsResolved()
assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN);
}
+ // gh-7011
+ @Test
+ public void resolveWhenQueryParameterIsEmptyAndSupportedThenOAuth2AuthenticationException() {
+ this.converter.setAllowUriQueryParameter(true);
+
+ MockServerHttpRequest.BaseBuilder> request = MockServerHttpRequest
+ .get("/")
+ .queryParam("access_token", "");
+
+ OAuth2AuthenticationException expected = catchThrowableOfType(() -> convertToToken(request),
+ OAuth2AuthenticationException.class);
+ BearerTokenError error = (BearerTokenError) expected.getError();
+ assertThat(error.getErrorCode()).isEqualTo(BearerTokenErrorCodes.INVALID_TOKEN);
+ assertThat(error.getUri()).isEqualTo("https://tools.ietf.org/html/rfc6750#section-3.1");
+ assertThat(error.getHttpStatus()).isEqualTo(HttpStatus.UNAUTHORIZED);
+ }
+
@Test
public void resolveWhenQueryParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
MockServerHttpRequest.BaseBuilder> request = MockServerHttpRequest
diff --git a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
index d176bd694ca..022aa7dd1ee 100644
--- a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
+++ b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -255,42 +255,6 @@ public void requestAuthorizationCodeGrantWhenInvalidStateParamThenDisplayLoginPa
assertThat(errorElement.asText()).contains("authorization_request_not_found");
}
- @Test
- public void requestAuthorizationCodeGrantWhenInvalidRedirectUriThenDisplayLoginPageWithError() throws Exception {
- HtmlPage page = this.webClient.getPage("/");
- URL loginPageUrl = page.getBaseURL();
- URL loginErrorPageUrl = new URL(loginPageUrl.toString() + "?error");
-
- ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId("google");
-
- HtmlAnchor clientAnchorElement = this.getClientAnchorElement(page, clientRegistration);
- assertThat(clientAnchorElement).isNotNull();
-
- WebResponse response = this.followLinkDisableRedirects(clientAnchorElement);
-
- UriComponents authorizeRequestUriComponents = UriComponentsBuilder.fromUri(
- URI.create(response.getResponseHeaderValue("Location"))).build();
-
- Map params = authorizeRequestUriComponents.getQueryParams().toSingleValueMap();
- String code = "auth-code";
- String state = URLDecoder.decode(params.get(OAuth2ParameterNames.STATE), "UTF-8");
- String redirectUri = URLDecoder.decode(params.get(OAuth2ParameterNames.REDIRECT_URI), "UTF-8");
- redirectUri += "-invalid";
-
- String authorizationResponseUri =
- UriComponentsBuilder.fromHttpUrl(redirectUri)
- .queryParam(OAuth2ParameterNames.CODE, code)
- .queryParam(OAuth2ParameterNames.STATE, state)
- .build().encode().toUriString();
-
- page = this.webClient.getPage(new URL(authorizationResponseUri));
- assertThat(page.getBaseURL()).isEqualTo(loginErrorPageUrl);
-
- HtmlElement errorElement = page.getBody().getFirstByXPath("div");
- assertThat(errorElement).isNotNull();
- assertThat(errorElement.asText()).contains("invalid_redirect_uri_parameter");
- }
-
private void assertLoginPage(HtmlPage page) throws Exception {
assertThat(page.getTitleText()).isEqualTo("Please sign in");
diff --git a/samples/xml/cas/cassample/src/integration-test/groovy/org/springframework/security/samples/cas/JettyCasService.groovy b/samples/xml/cas/cassample/src/integration-test/groovy/org/springframework/security/samples/cas/JettyCasService.groovy
index b5b8f2feb35..8be5860fb20 100644
--- a/samples/xml/cas/cassample/src/integration-test/groovy/org/springframework/security/samples/cas/JettyCasService.groovy
+++ b/samples/xml/cas/cassample/src/integration-test/groovy/org/springframework/security/samples/cas/JettyCasService.groovy
@@ -66,7 +66,7 @@ class JettyCasService extends Server {
String password = System.getProperty('javax.net.ssl.trustStorePassword','password')
- SslContextFactory sslContextFactory = new SslContextFactory();
+ SslContextFactory sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(getTrustStore());
sslContextFactory.setKeyStorePassword(password);
sslContextFactory.setKeyManagerPassword(password);
diff --git a/scripts/release/release-notes-sections.yml b/scripts/release/release-notes-sections.yml
new file mode 100644
index 00000000000..574c8cfbec6
--- /dev/null
+++ b/scripts/release/release-notes-sections.yml
@@ -0,0 +1,14 @@
+releasenotes:
+ sections:
+ - title: "New Features"
+ emoji: ":star:"
+ labels: ["enhancement"]
+ - title: "Bug Fixes"
+ emoji: ":beetle:"
+ labels: ["bug", "regression"]
+ - title: "Dependency Upgrades"
+ emoji: ":hammer:"
+ labels: ["dependency-upgrade"]
+ - title: "Non-passive"
+ emoji: ":rewind:"
+ labels: ["breaks-passivity"]
diff --git a/scripts/release/wait-for-done b/scripts/release/wait-for-done
new file mode 100755
index 00000000000..7bd50205ed0
--- /dev/null
+++ b/scripts/release/wait-for-done
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+VERSION=$1
+until http -h --check-status --ignore-stdin https://repo1.maven.org/maven2/org/springframework/security/spring-security-core/$VERSION/; do sleep 10; clear; done; spd-say "It is now uploaded"
diff --git a/test/spring-security-test.gradle b/test/spring-security-test.gradle
index 35174aa77cd..6474f133054 100644
--- a/test/spring-security-test.gradle
+++ b/test/spring-security-test.gradle
@@ -12,6 +12,7 @@ dependencies {
provided 'javax.servlet:javax.servlet-api'
+ testCompile project(path : ':spring-security-config', configuration : 'tests')
testCompile 'com.fasterxml.jackson.core:jackson-databind'
testCompile 'io.projectreactor:reactor-test'
testCompile 'javax.xml.bind:jaxb-api'
diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java b/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java
index 8c11be54dbf..d2cc86d9660 100644
--- a/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java
+++ b/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java
@@ -43,7 +43,7 @@ public SecurityContext createSecurityContext(WithMockUser withUser) {
.username() : withUser.value();
if (username == null) {
throw new IllegalArgumentException(withUser
- + " cannot have null username on both username and value properites");
+ + " cannot have null username on both username and value properties");
}
List grantedAuthorities = new ArrayList<>();
diff --git a/test/src/main/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurer.java b/test/src/main/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurer.java
index 909a92fee9e..f654fcd7558 100644
--- a/test/src/main/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurer.java
+++ b/test/src/main/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurer.java
@@ -16,6 +16,11 @@
package org.springframework.security.test.web.servlet.setup;
import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import org.springframework.security.config.BeanIds;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
@@ -23,6 +28,8 @@
import org.springframework.test.web.servlet.setup.MockMvcConfigurerAdapter;
import org.springframework.web.context.WebApplicationContext;
+import java.io.IOException;
+
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext;
/**
@@ -34,12 +41,13 @@
* @since 4.0
*/
final class SecurityMockMvcConfigurer extends MockMvcConfigurerAdapter {
- private Filter springSecurityFilterChain;
+ private final DelegateFilter delegateFilter;
/**
* Creates a new instance
*/
SecurityMockMvcConfigurer() {
+ this.delegateFilter = new DelegateFilter();
}
/**
@@ -47,30 +55,101 @@ final class SecurityMockMvcConfigurer extends MockMvcConfigurerAdapter {
* @param springSecurityFilterChain the {@link javax.servlet.Filter} to use
*/
SecurityMockMvcConfigurer(Filter springSecurityFilterChain) {
- this.springSecurityFilterChain = springSecurityFilterChain;
+ this.delegateFilter = new DelegateFilter(springSecurityFilterChain);
+ }
+
+ @Override
+ public void afterConfigurerAdded(ConfigurableMockMvcBuilder> builder) {
+ builder.addFilters(this.delegateFilter);
}
@Override
public RequestPostProcessor beforeMockMvcCreated(
ConfigurableMockMvcBuilder> builder, WebApplicationContext context) {
String securityBeanId = BeanIds.SPRING_SECURITY_FILTER_CHAIN;
- if (this.springSecurityFilterChain == null
+ if (getSpringSecurityFilterChain() == null
&& context.containsBean(securityBeanId)) {
- this.springSecurityFilterChain = context.getBean(securityBeanId,
- Filter.class);
+ setSpringSecurityFitlerChain(context.getBean(securityBeanId,
+ Filter.class));
}
- if (this.springSecurityFilterChain == null) {
+ if (getSpringSecurityFilterChain() == null) {
throw new IllegalStateException(
"springSecurityFilterChain cannot be null. Ensure a Bean with the name "
+ securityBeanId
+ " implementing Filter is present or inject the Filter to be used.");
}
- builder.addFilters(this.springSecurityFilterChain);
+ // This is used by other test support to obtain the FilterChainProxy
context.getServletContext().setAttribute(BeanIds.SPRING_SECURITY_FILTER_CHAIN,
- this.springSecurityFilterChain);
+ getSpringSecurityFilterChain());
return testSecurityContext();
}
+
+ private void setSpringSecurityFitlerChain(Filter filter) {
+ this.delegateFilter.setDelegate(filter);
+ }
+
+ private Filter getSpringSecurityFilterChain() {
+ return this.delegateFilter.delegate;
+ }
+
+ /**
+ * Allows adding in {@link #afterConfigurerAdded(ConfigurableMockMvcBuilder)} to preserve Filter order and then
+ * lazily set the delegate in {@link #beforeMockMvcCreated(ConfigurableMockMvcBuilder, WebApplicationContext)}.
+ *
+ * {@link org.springframework.web.filter.DelegatingFilterProxy} is not used because it is not easy to lazily set
+ * the delegate or get the delegate which is necessary for the test infrastructure.
+ */
+ static class DelegateFilter implements Filter {
+
+ private Filter delegate;
+
+ DelegateFilter() {
+ }
+
+ DelegateFilter(Filter delegate) {
+ this.delegate = delegate;
+ }
+
+ void setDelegate(Filter delegate) {
+ this.delegate = delegate;
+ }
+
+ Filter getDelegate() {
+ return this.delegate;
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ this.delegate.init(filterConfig);
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ this.delegate.doFilter(request, response, chain);
+ }
+
+ @Override
+ public void destroy() {
+ this.delegate.destroy();
+ }
+
+ @Override
+ public int hashCode() {
+ return this.delegate.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this.delegate.equals(obj);
+ }
+
+ @Override
+ public String toString() {
+ return this.delegate.toString();
+ }
+ }
}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationTests.java
index 77ba524777e..40289bd9b4b 100644
--- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationTests.java
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationTests.java
@@ -44,7 +44,7 @@
@RunWith(PowerMockRunner.class)
@PrepareOnlyThisForTest(WebTestUtils.class)
-@PowerMockIgnore("javax.security.auth.*")
+@PowerMockIgnore({"javax.security.auth.*", "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*"})
public class SecurityMockMvcRequestPostProcessorsAuthenticationTests {
@Captor
private ArgumentCaptor contextCaptor;
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsSecurityContextTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsSecurityContextTests.java
index 4242971683c..005599649e2 100644
--- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsSecurityContextTests.java
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsSecurityContextTests.java
@@ -32,6 +32,7 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -42,6 +43,7 @@
@RunWith(PowerMockRunner.class)
@PrepareOnlyThisForTest(WebTestUtils.class)
+@PowerMockIgnore({"javax.security.auth.*", "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*"})
public class SecurityMockMvcRequestPostProcessorsSecurityContextTests {
@Captor
private ArgumentCaptor contextCaptor;
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextTests.java
index b87d3efd000..65ed0f969b4 100644
--- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextTests.java
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextTests.java
@@ -29,6 +29,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -39,6 +40,7 @@
@RunWith(PowerMockRunner.class)
@PrepareOnlyThisForTest(WebTestUtils.class)
+@PowerMockIgnore({"javax.security.auth.*", "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*"})
public class SecurityMockMvcRequestPostProcessorsTestSecurityContextTests {
@Mock
private SecurityContext context;
@@ -81,4 +83,4 @@ private void mockWebTestUtils() {
spy(WebTestUtils.class);
when(WebTestUtils.getSecurityContextRepository(request)).thenReturn(repository);
}
-}
\ No newline at end of file
+}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserDetailsTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserDetailsTests.java
index 0b1a391b630..20bd7caed7f 100644
--- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserDetailsTests.java
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserDetailsTests.java
@@ -32,6 +32,7 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -44,6 +45,7 @@
@RunWith(PowerMockRunner.class)
@PrepareOnlyThisForTest(WebTestUtils.class)
+@PowerMockIgnore({"javax.security.auth.*", "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*"})
public class SecurityMockMvcRequestPostProcessorsUserDetailsTests {
@Captor
private ArgumentCaptor contextCaptor;
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserTests.java
index f29f3fb78a3..23bfa8715fa 100644
--- a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserTests.java
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserTests.java
@@ -35,6 +35,7 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -47,6 +48,7 @@
@RunWith(PowerMockRunner.class)
@PrepareOnlyThisForTest(WebTestUtils.class)
+@PowerMockIgnore({"javax.security.auth.*", "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*"})
public class SecurityMockMvcRequestPostProcessorsUserTests {
@Captor
private ArgumentCaptor contextCaptor;
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurerTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurerTests.java
index 41df811a1fe..eb4c41567f5 100644
--- a/test/src/test/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurerTests.java
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurerTests.java
@@ -15,21 +15,24 @@
*/
package org.springframework.security.test.web.servlet.setup;
-import javax.servlet.Filter;
-import javax.servlet.ServletContext;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
-
import org.springframework.security.config.BeanIds;
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
import org.springframework.web.context.WebApplicationContext;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
+import javax.servlet.Filter;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -56,9 +59,10 @@ public void beforeMockMvcCreatedOverrideBean() throws Exception {
returnFilterBean();
SecurityMockMvcConfigurer configurer = new SecurityMockMvcConfigurer(this.filter);
+ configurer.afterConfigurerAdded(this.builder);
configurer.beforeMockMvcCreated(this.builder, this.context);
- verify(this.builder).addFilters(this.filter);
+ assertFilterAdded(this.filter);
verify(this.servletContext).setAttribute(BeanIds.SPRING_SECURITY_FILTER_CHAIN,
this.filter);
}
@@ -68,27 +72,37 @@ public void beforeMockMvcCreatedBean() throws Exception {
returnFilterBean();
SecurityMockMvcConfigurer configurer = new SecurityMockMvcConfigurer();
+ configurer.afterConfigurerAdded(this.builder);
configurer.beforeMockMvcCreated(this.builder, this.context);
- verify(this.builder).addFilters(this.beanFilter);
+ assertFilterAdded(this.beanFilter);
}
@Test
public void beforeMockMvcCreatedNoBean() throws Exception {
SecurityMockMvcConfigurer configurer = new SecurityMockMvcConfigurer(this.filter);
+ configurer.afterConfigurerAdded(this.builder);
configurer.beforeMockMvcCreated(this.builder, this.context);
- verify(this.builder).addFilters(this.filter);
+ assertFilterAdded(this.filter);
}
@Test(expected = IllegalStateException.class)
public void beforeMockMvcCreatedNoFilter() throws Exception {
SecurityMockMvcConfigurer configurer = new SecurityMockMvcConfigurer();
+ configurer.afterConfigurerAdded(this.builder);
configurer.beforeMockMvcCreated(this.builder, this.context);
}
+ private void assertFilterAdded(Filter filter) throws IOException, ServletException {
+ ArgumentCaptor filterArg = ArgumentCaptor.forClass(
+ SecurityMockMvcConfigurer.DelegateFilter.class);
+ verify(this.builder).addFilters(filterArg.capture());
+ assertThat(filterArg.getValue().getDelegate()).isEqualTo(filter);
+ }
+
private void returnFilterBean() {
when(this.context.containsBean(anyString())).thenReturn(true);
when(this.context.getBean(anyString(), eq(Filter.class)))
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurersTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurersTests.java
new file mode 100644
index 00000000000..162114d6ee8
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/setup/SecurityMockMvcConfigurersTests.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.test.web.servlet.setup;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.users.AuthenticationTestConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import javax.servlet.Filter;
+
+import static org.mockito.Mockito.mock;
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author Rob Winch
+ */
+@RunWith(SpringRunner.class)
+@WebAppConfiguration
+public class SecurityMockMvcConfigurersTests {
+ @Autowired
+ WebApplicationContext wac;
+
+ Filter noOpFilter = mock(Filter.class);
+
+ /**
+ * Since noOpFilter is first does not continue the chain, security will not be invoked and the status should be OK
+ *
+ * @throws Exception
+ */
+ @Test
+ public void applySpringSecurityWhenAddFilterFirstThenFilterFirst() throws Exception {
+ MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
+ .addFilters(this.noOpFilter)
+ .apply(springSecurity())
+ .build();
+
+ mockMvc.perform(get("/"))
+ .andExpect(status().isOk());
+ }
+
+ /**
+ * Since noOpFilter is second security will be invoked and the status will be not OK. We know this because if noOpFilter
+ * were first security would not be invoked sincet noOpFilter does not continue the FilterChain
+ * @throws Exception
+ */
+ @Test
+ public void applySpringSecurityWhenAddFilterSecondThenSecurityFirst() throws Exception {
+ MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
+ .apply(springSecurity())
+ .addFilters(this.noOpFilter)
+ .build();
+
+ mockMvc.perform(get("/"))
+ .andExpect(status().is4xxClientError());
+ }
+
+ @Configuration
+ @EnableWebMvc
+ @EnableWebSecurity
+ @Import(AuthenticationTestConfiguration.class)
+ static class Config {}
+}
diff --git a/web/src/main/java/org/springframework/security/web/FilterChainProxy.java b/web/src/main/java/org/springframework/security/web/FilterChainProxy.java
index b4157c8921c..d0d348b7517 100644
--- a/web/src/main/java/org/springframework/security/web/FilterChainProxy.java
+++ b/web/src/main/java/org/springframework/security/web/FilterChainProxy.java
@@ -60,7 +60,7 @@
* requests which match the pattern. An example configuration might look like this:
*
*
- * <bean id="myfilterChainProxy" class="org.springframework.security.util.FilterChainProxy">
+ * <bean id="myfilterChainProxy" class="org.springframework.security.web.FilterChainProxy">
* <constructor-arg>
* <util:list>
* <security:filter-chain pattern="/do/not/filter*" filters="none"/>
diff --git a/web/src/main/java/org/springframework/security/web/FilterInvocation.java b/web/src/main/java/org/springframework/security/web/FilterInvocation.java
index 5e762118d8d..e85ce6fe390 100644
--- a/web/src/main/java/org/springframework/security/web/FilterInvocation.java
+++ b/web/src/main/java/org/springframework/security/web/FilterInvocation.java
@@ -228,10 +228,15 @@ public String getQueryString() {
public void setQueryString(String queryString) {
this.queryString = queryString;
}
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
}
final class UnsupportedOperationExceptionInvocationHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
throw new UnsupportedOperationException(method + " is not supported");
}
-}
\ No newline at end of file
+}
diff --git a/web/src/main/java/org/springframework/security/web/authentication/session/ConcurrentSessionControlAuthenticationStrategy.java b/web/src/main/java/org/springframework/security/web/authentication/session/ConcurrentSessionControlAuthenticationStrategy.java
index 68df38f9025..2e7401207c6 100644
--- a/web/src/main/java/org/springframework/security/web/authentication/session/ConcurrentSessionControlAuthenticationStrategy.java
+++ b/web/src/main/java/org/springframework/security/web/authentication/session/ConcurrentSessionControlAuthenticationStrategy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/
package org.springframework.security.web.authentication.session;
+import java.util.Comparator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@@ -45,8 +46,9 @@
*
*
* If a user has reached the maximum number of permitted sessions, the behaviour depends
- * on the exceptionIfMaxExceeded property. The default behaviour is to expired
- * the least recently used session, which will be invalidated by the
+ * on the exceptionIfMaxExceeded property. The default behaviour is to expire
+ * any sessions that exceed the maximum number of permitted sessions, starting with the
+ * least recently used sessions. The expired sessions will be invalidated by the
* {@link ConcurrentSessionFilter} if accessed again. If exceptionIfMaxExceeded
* is set to true , however, the user will be prevented from starting a new
* authenticated session.
@@ -156,18 +158,13 @@ protected void allowableSessionsExceeded(List sessions,
"Maximum sessions of {0} for this principal exceeded"));
}
- // Determine least recently used session, and mark it for invalidation
- SessionInformation leastRecentlyUsed = null;
-
- for (SessionInformation session : sessions) {
- if ((leastRecentlyUsed == null)
- || session.getLastRequest()
- .before(leastRecentlyUsed.getLastRequest())) {
- leastRecentlyUsed = session;
- }
+ // Determine least recently used sessions, and mark them for invalidation
+ sessions.sort(Comparator.comparing(SessionInformation::getLastRequest));
+ int maximumSessionsExceededBy = sessions.size() - allowableSessions + 1;
+ List sessionsToBeExpired = sessions.subList(0, maximumSessionsExceededBy);
+ for (SessionInformation session: sessionsToBeExpired) {
+ session.expireNow();
}
-
- leastRecentlyUsed.expireNow();
}
/**
diff --git a/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java b/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java
index c460f5a5220..e7863b90acf 100644
--- a/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java
+++ b/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java
@@ -563,6 +563,6 @@ public void setSwitchAuthorityRole(String switchAuthorityRole) {
}
private static RequestMatcher createMatcher(String pattern) {
- return new AntPathRequestMatcher(pattern, null, true, new UrlPathHelper());
+ return new AntPathRequestMatcher(pattern, "POST", true, new UrlPathHelper());
}
}
diff --git a/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java b/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java
index 643b1e7b588..6e7afc73e0a 100644
--- a/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java
+++ b/web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2020 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,16 +16,17 @@
package org.springframework.security.web.firewall;
-import org.springframework.http.HttpMethod;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Predicate;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.http.HttpMethod;
/**
*
@@ -66,10 +67,15 @@
* Rejects URLs that contain a URL encoded percent. See
* {@link #setAllowUrlEncodedPercent(boolean)}
*
+ *
+ * Rejects hosts that are not allowed. See
+ * {@link #setAllowedHostnames(Predicate)}
+ *
*
*
* @see DefaultHttpFirewall
* @author Rob Winch
+ * @author Eddú Meléndez
* @since 4.2.4
*/
public class StrictHttpFirewall implements HttpFirewall {
@@ -96,6 +102,8 @@ public class StrictHttpFirewall implements HttpFirewall {
private Set allowedHttpMethods = createDefaultAllowedHttpMethods();
+ private Predicate allowedHostnames = hostname -> true;
+
public StrictHttpFirewall() {
urlBlacklistsAddAll(FORBIDDEN_SEMICOLON);
urlBlacklistsAddAll(FORBIDDEN_FORWARDSLASH);
@@ -277,6 +285,21 @@ public void setAllowUrlEncodedPercent(boolean allowUrlEncodedPercent) {
}
}
+ /**
+ *
+ * Determines which hostnames should be allowed. The default is to allow any hostname.
+ *
+ *
+ * @param allowedHostnames the predicate for testing hostnames
+ * @since 5.1.11
+ */
+ public void setAllowedHostnames(Predicate allowedHostnames) {
+ if (allowedHostnames == null) {
+ throw new IllegalArgumentException("allowedHostnames cannot be null");
+ }
+ this.allowedHostnames = allowedHostnames;
+ }
+
private void urlBlacklistsAddAll(Collection values) {
this.encodedUrlBlacklist.addAll(values);
this.decodedUrlBlacklist.addAll(values);
@@ -291,6 +314,7 @@ private void urlBlacklistsRemoveAll(Collection values) {
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
rejectForbiddenHttpMethod(request);
rejectedBlacklistedUrls(request);
+ rejectedUntrustedHosts(request);
if (!isNormalized(request)) {
throw new RequestRejectedException("The request was rejected because the URL was not normalized.");
@@ -332,6 +356,13 @@ private void rejectedBlacklistedUrls(HttpServletRequest request) {
}
}
+ private void rejectedUntrustedHosts(HttpServletRequest request) {
+ String serverName = request.getServerName();
+ if (serverName != null && !this.allowedHostnames.test(serverName)) {
+ throw new RequestRejectedException("The request was rejected because the domain " + serverName + " is untrusted.");
+ }
+ }
+
@Override
public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
return new FirewalledResponse(response);
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/DelegatingServerAuthenticationSuccessHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/DelegatingServerAuthenticationSuccessHandler.java
index 2fafd24becf..019442b5af3 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/DelegatingServerAuthenticationSuccessHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/DelegatingServerAuthenticationSuccessHandler.java
@@ -19,12 +19,11 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.util.Assert;
+import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* Delegates to a collection of {@link ServerAuthenticationSuccessHandler} implementations.
@@ -43,7 +42,8 @@ public DelegatingServerAuthenticationSuccessHandler(ServerAuthenticationSuccessH
@Override
public Mono onAuthenticationSuccess(WebFilterExchange exchange,
Authentication authentication) {
- Stream> results = this.delegates.stream().map(delegate -> delegate.onAuthenticationSuccess(exchange, authentication));
- return Mono.when(results.collect(Collectors.toList()));
+ return Flux.fromIterable(this.delegates)
+ .concatMap(delegate -> delegate.onAuthenticationSuccess(exchange, authentication))
+ .then();
}
}
diff --git a/web/src/main/java/org/springframework/security/web/server/authentication/logout/DelegatingServerLogoutHandler.java b/web/src/main/java/org/springframework/security/web/server/authentication/logout/DelegatingServerLogoutHandler.java
index 197f3565357..9b6567227d1 100644
--- a/web/src/main/java/org/springframework/security/web/server/authentication/logout/DelegatingServerLogoutHandler.java
+++ b/web/src/main/java/org/springframework/security/web/server/authentication/logout/DelegatingServerLogoutHandler.java
@@ -20,9 +20,8 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
+import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.security.core.Authentication;
@@ -50,10 +49,8 @@ public DelegatingServerLogoutHandler(Collection delegates)
@Override
public Mono logout(WebFilterExchange exchange, Authentication authentication) {
- return Mono.when(this.delegates.stream()
- .filter(Objects::nonNull)
- .map(delegate -> delegate.logout(exchange, authentication))
- .collect(Collectors.toList())
- );
+ return Flux.fromIterable(this.delegates)
+ .concatMap(delegate -> delegate.logout(exchange, authentication))
+ .then();
}
}
diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/CsrfWebFilter.java b/web/src/main/java/org/springframework/security/web/server/csrf/CsrfWebFilter.java
index a74fc3384d3..d434ebe673f 100644
--- a/web/src/main/java/org/springframework/security/web/server/csrf/CsrfWebFilter.java
+++ b/web/src/main/java/org/springframework/security/web/server/csrf/CsrfWebFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -55,6 +55,7 @@
*
*
* @author Rob Winch
+ * @author Parikshit Dutta
* @since 5.0
*/
public class CsrfWebFilter implements WebFilter {
@@ -136,7 +137,7 @@ private static class DefaultRequireCsrfProtectionMatcher implements ServerWebExc
@Override
public Mono matches(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest())
- .map(r -> r.getMethod())
+ .flatMap(r -> Mono.justOrEmpty(r.getMethod()))
.filter(m -> ALLOWED_METHODS.contains(m))
.flatMap(m -> MatchResult.notMatch())
.switchIfEmpty(MatchResult.match());
diff --git a/web/src/main/java/org/springframework/security/web/server/header/CompositeServerHttpHeadersWriter.java b/web/src/main/java/org/springframework/security/web/server/header/CompositeServerHttpHeadersWriter.java
index bb28c4b2c8c..f5fcf0f9d62 100644
--- a/web/src/main/java/org/springframework/security/web/server/header/CompositeServerHttpHeadersWriter.java
+++ b/web/src/main/java/org/springframework/security/web/server/header/CompositeServerHttpHeadersWriter.java
@@ -15,15 +15,13 @@
*/
package org.springframework.security.web.server.header;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
import org.springframework.web.server.ServerWebExchange;
-
+import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Combines multiple {@link ServerHttpHeadersWriter} instances into a single instance.
*
@@ -43,8 +41,9 @@ public CompositeServerHttpHeadersWriter(List writers) {
@Override
public Mono writeHttpHeaders(ServerWebExchange exchange) {
- Stream> results = writers.stream().map( writer -> writer.writeHttpHeaders(exchange));
- return Mono.when(results.collect(Collectors.toList()));
+ return Flux.fromIterable(this.writers)
+ .concatMap(w -> w.writeHttpHeaders(exchange))
+ .then();
}
}
diff --git a/web/src/main/java/org/springframework/security/web/server/ui/LoginPageGeneratingWebFilter.java b/web/src/main/java/org/springframework/security/web/server/ui/LoginPageGeneratingWebFilter.java
index 2c760654c21..5daa3f00127 100644
--- a/web/src/main/java/org/springframework/security/web/server/ui/LoginPageGeneratingWebFilter.java
+++ b/web/src/main/java/org/springframework/security/web/server/ui/LoginPageGeneratingWebFilter.java
@@ -106,7 +106,7 @@ private byte[] createPage(ServerWebExchange exchange, String csrfTokenHtmlInput)
+ " \n"
+ " \n"
+ formLogin(queryParams, csrfTokenHtmlInput)
- + oauth2LoginLinks(contextPath, this.oauth2AuthenticationUrlToClientName)
+ + oauth2LoginLinks(queryParams, contextPath, this.oauth2AuthenticationUrlToClientName)
+ "
\n"
+ " \n"
+ "