瀏覽代碼

Remove Deprecated OpenSAML 3 Support

Closes gh-10556
Rob Winch 3 年之前
父節點
當前提交
48e31f87e4
共有 25 個文件被更改,包括 14 次插入2227 次删除
  1. 0 8
      build.gradle
  2. 1 1
      config/spring-security-config.gradle
  3. 6 31
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurer.java
  4. 2 29
      config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java
  5. 0 21
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java
  6. 0 8
      docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc
  7. 2 0
      docs/modules/ROOT/pages/whats-new.adoc
  8. 1 1
      gradle.properties
  9. 0 79
      saml2/saml2-service-provider/spring-security-saml2-service-provider.gradle
  10. 1 1
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java
  11. 0 0
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolver.java
  12. 0 0
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolver.java
  13. 0 0
      saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java
  14. 0 864
      saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java
  15. 0 112
      saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml3AuthenticationRequestResolver.java
  16. 0 124
      saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolver.java
  17. 0 120
      saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolver.java
  18. 0 682
      saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProviderTests.java
  19. 0 66
      saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolverTests.java
  20. 0 78
      saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolverTests.java
  21. 1 2
      saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipalTests.java
  22. 0 0
      saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java
  23. 0 0
      saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolverTests.java
  24. 0 0
      saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolverTests.java
  25. 0 0
      saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java

+ 0 - 8
build.gradle

@@ -118,14 +118,6 @@ updateDependenciesSettings {
 					selection.reject("nimbus-jose-jwt gets updated when oauth2-oidc-sdk is updated to ensure consistency");
 				}
 			}
-			components.all { selection ->
-				ModuleComponentIdentifier candidate = selection.getCandidate();
-				// Do not compare version due to multiple versions existing
-				// will cause opensaml 3.x to be updated to 4.x
-				if (candidate.getGroup().equals("org.opensaml")) {
-					selection.reject("org.opensaml maintains two different versions, so it must be updated manually");
-				}
-			}
 		}
 	}
 }

+ 1 - 1
config/spring-security-config.gradle

@@ -46,8 +46,8 @@ dependencies {
 	testImplementation project(path : ':spring-security-ldap', configuration : 'tests')
 	testImplementation project(path : ':spring-security-oauth2-client', configuration : 'tests')
 	testImplementation project(path : ':spring-security-oauth2-resource-server', configuration : 'tests')
+	testImplementation project(':spring-security-saml2-service-provider')
 	testImplementation project(path : ':spring-security-saml2-service-provider', configuration : 'tests')
-	testImplementation project(path : ':spring-security-saml2-service-provider', configuration : 'opensaml4MainImplementation')
 	testImplementation project(path : ':spring-security-web', configuration : 'tests')
 	testImplementation "jakarta.inject:jakarta.inject-api"
 	testImplementation "org.assertj:assertj-core"

+ 6 - 31
config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurer.java

@@ -19,8 +19,6 @@ package org.springframework.security.config.annotation.web.configurers.saml2;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import org.opensaml.core.Version;
-
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.security.authentication.AuthenticationManager;
@@ -33,7 +31,6 @@ import org.springframework.security.config.annotation.web.configurers.CsrfConfig
 import org.springframework.security.core.Authentication;
 import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
 import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
-import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider;
 import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
 import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
 import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
@@ -43,7 +40,6 @@ import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2A
 import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
 import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
 import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
-import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml3AuthenticationRequestResolver;
 import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
 import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
 import org.springframework.security.web.AuthenticationEntryPoint;
@@ -200,10 +196,6 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
 	 * @since 6.0
 	 */
 	public Saml2LoginConfigurer<B> authenticationRequestUri(String authenticationRequestUri) {
-		// OpenSAML 3 is no longer supported by spring security
-		if (version().startsWith("3")) {
-			return this;
-		}
 		Assert.state(authenticationRequestUri.contains("{registrationId}"),
 				"authenticationRequestUri must contain {registrationId} path variable");
 		this.authenticationRequestUri = authenticationRequestUri;
@@ -345,14 +337,11 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
 		if (bean != null) {
 			return bean;
 		}
-		if (version().startsWith("4")) {
-			OpenSaml4AuthenticationRequestResolver openSaml4AuthenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver(
-					relyingPartyRegistrationResolver(http));
-			openSaml4AuthenticationRequestResolver
-					.setRequestMatcher(new AntPathRequestMatcher(this.authenticationRequestUri));
-			return openSaml4AuthenticationRequestResolver;
-		}
-		return new OpenSaml3AuthenticationRequestResolver(relyingPartyRegistrationResolver(http));
+		OpenSaml4AuthenticationRequestResolver openSaml4AuthenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver(
+				relyingPartyRegistrationResolver(http));
+		openSaml4AuthenticationRequestResolver
+				.setRequestMatcher(new AntPathRequestMatcher(this.authenticationRequestUri));
+		return openSaml4AuthenticationRequestResolver;
 	}
 
 	private AuthenticationConverter getAuthenticationConverter(B http) {
@@ -370,22 +359,8 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
 		return authenticationConverterBean;
 	}
 
-	private String version() {
-		String version = Version.getVersion();
-		if (version != null) {
-			return version;
-		}
-		return Version.class.getModule().getDescriptor().version().map(Object::toString)
-				.orElseThrow(() -> new IllegalStateException("cannot determine OpenSAML version"));
-	}
-
 	private void registerDefaultAuthenticationProvider(B http) {
-		if (version().startsWith("4")) {
-			http.authenticationProvider(postProcess(new OpenSaml4AuthenticationProvider()));
-		}
-		else {
-			http.authenticationProvider(postProcess(new OpenSamlAuthenticationProvider()));
-		}
+		http.authenticationProvider(postProcess(new OpenSaml4AuthenticationProvider()));
 	}
 
 	private void registerDefaultCsrfOverride(B http) {

+ 2 - 29
config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java

@@ -22,8 +22,6 @@ import java.util.Objects;
 import java.util.function.Predicate;
 
 import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.opensaml.core.Version;
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.security.authentication.AuthenticationManager;
@@ -44,8 +42,6 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
 import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
 import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
 import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository;
-import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml3LogoutRequestResolver;
-import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml3LogoutResponseResolver;
 import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver;
 import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver;
 import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
@@ -313,15 +309,6 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
 		return this.context.getBean(clazz);
 	}
 
-	private String version() {
-		String version = Version.getVersion();
-		if (version != null) {
-			return version;
-		}
-		return Version.class.getModule().getDescriptor().version().map(Object::toString)
-				.orElseThrow(() -> new IllegalStateException("cannot determine OpenSAML version"));
-	}
-
 	/**
 	 * A configurer for SAML 2.0 LogoutRequest components
 	 */
@@ -401,10 +388,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
 			if (this.logoutRequestResolver != null) {
 				return this.logoutRequestResolver;
 			}
-			if (version().startsWith("4")) {
-				return new OpenSaml4LogoutRequestResolver(relyingPartyRegistrationResolver);
-			}
-			return new OpenSaml3LogoutRequestResolver(relyingPartyRegistrationResolver);
+			return new OpenSaml4LogoutRequestResolver(relyingPartyRegistrationResolver);
 		}
 
 	}
@@ -471,10 +455,7 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
 		private Saml2LogoutResponseResolver logoutResponseResolver(
 				RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
 			if (this.logoutResponseResolver == null) {
-				if (version().startsWith("4")) {
-					return new OpenSaml4LogoutResponseResolver(relyingPartyRegistrationResolver);
-				}
-				return new OpenSaml3LogoutResponseResolver(relyingPartyRegistrationResolver);
+				return new OpenSaml4LogoutResponseResolver(relyingPartyRegistrationResolver);
 			}
 			return this.logoutResponseResolver;
 		}
@@ -511,12 +492,4 @@ public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
 
 	}
 
-	private static class NoopLogoutHandler implements LogoutHandler {
-
-		@Override
-		public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
-		}
-
-	}
-
 }

文件差異過大導致無法顯示
+ 0 - 21
config/src/test/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurerTests.java


+ 0 - 8
docs/modules/ROOT/pages/servlet/saml2/login/overview.adoc

@@ -154,14 +154,6 @@ Instead, such classes as `OpenSamlAuthenticationRequestFactory` and `OpenSamlAut
 
 For example, once your application receives a `SAMLResponse` and delegates to `Saml2WebSsoAuthenticationFilter`, the filter delegates to `OpenSamlAuthenticationProvider`:
 
-[NOTE]
-====
-For backward compatibility, Spring Security will use the latest OpenSAML 3 by default.
-Note, though that OpenSAML 3 has reached it's end-of-life and updating to OpenSAML 4.x is recommended.
-For that reason, Spring Security supports both OpenSAML 3.x and 4.x.
-If you manage your OpenSAML dependency to 4.x, then Spring Security will select its OpenSAML 4.x implementations.
-====
-
 .Authenticating an OpenSAML `Response`
 image:{figures}/opensamlauthenticationprovider.png[]
 

+ 2 - 0
docs/modules/ROOT/pages/whats-new.adoc

@@ -6,6 +6,8 @@ Below are the highlights of the release.
 
 == Breaking Changes
 
+* https://github.com/spring-projects/spring-security/issues/10556[gh-10556] - Remove EOL OpenSaml 3 Support.
+Use the OpenSaml 4 Support instead.
 * https://github.com/spring-projects/spring-security/issues/8980[gh-8980] - Remove unsafe/deprecated `Encryptors.querableText(CharSequence,CharSequence)`.
 Instead use data storage to encrypt values.
 * https://github.com/spring-projects/spring-security/issues/11520[gh-11520] - Remember Me uses SHA256 by default

+ 1 - 1
gradle.properties

@@ -2,7 +2,7 @@ aspectjVersion=1.9.9.1
 springJavaformatVersion=0.0.34
 springBootVersion=2.4.2
 springFrameworkVersion=6.0.0-M6
-openSamlVersion=3.4.6
+openSamlVersion=4.1.1
 version=6.0.0-SNAPSHOT
 kotlinVersion=1.7.10
 samplesBranch=main

+ 0 - 79
saml2/saml2-service-provider/spring-security-saml2-service-provider.gradle

@@ -1,44 +1,4 @@
 apply plugin: 'io.spring.convention.spring-module'
-apply plugin: 'nebula.facet'
-
-facets {
-	opensaml3Main {
-		parentSourceSet = 'main'
-	}
-	opensaml4Main {
-		parentSourceSet = 'main'
-	}
-	opensaml3Test {
-		parentSourceSet = 'opensaml3Main'
-	}
-	opensaml4Test {
-		parentSourceSet = 'opensaml4Main'
-	}
-}
-
-sourceSets {
-	opensaml3Test {
-		compileClasspath += sourceSets.test.output
-		runtimeClasspath += sourceSets.test.output
-	}
-	opensaml4Test {
-		compileClasspath += sourceSets.test.output
-		runtimeClasspath += sourceSets.test.output
-	}
-}
-
-configurations {
-	opensaml3TestImplementation.extendsFrom testImplementation
-	opensaml4TestImplementation.extendsFrom testImplementation
-	opensaml4MainImplementation {
-		canBeConsumed = true
-	}
-}
-
-compileOpensaml4MainJava {
-	sourceCompatibility = JavaVersion.VERSION_17
-	targetCompatibility = JavaVersion.VERSION_17
-}
 
 dependencies {
 	management platform(project(":spring-security-dependencies"))
@@ -50,13 +10,6 @@ dependencies {
 	api ("org.opensaml:opensaml-saml-impl")  {
 		exclude group: 'commons-logging', module: 'commons-logging'
 	}
-	opensaml4MainImplementation "org.opensaml:opensaml-core:4.1.0"
-	opensaml4MainImplementation ("org.opensaml:opensaml-saml-api:4.1.0") {
-		exclude group: 'commons-logging', module: 'commons-logging'
-	}
-	opensaml4MainImplementation ("org.opensaml:opensaml-saml-impl:4.1.0") {
-		exclude group: 'commons-logging', module: 'commons-logging'
-	}
 
 	provided 'jakarta.servlet:jakarta.servlet-api'
 
@@ -73,35 +26,3 @@ dependencies {
 	testImplementation "org.mockito:mockito-junit-jupiter"
 	testImplementation "org.springframework:spring-test"
 }
-
-project.tasks.matching { t -> t.name == "jar"}.configureEach {
-	duplicatesStrategy = DuplicatesStrategy.EXCLUDE
-	from {
-		compileOpensaml3MainJava
-	}
-	from {
-		compileOpensaml4MainJava
-	}
-}
-
-project.tasks.matching { t -> t.name == "sourcesJar"}.configureEach {
-	from {
-		sourceSets.opensaml3Main.allSource
-	}
-	from {
-		sourceSets.opensaml4Main.allSource
-	}
-}
-
-
-javadoc {
-	source += sourceSets.opensaml3Main.allJava + sourceSets.opensaml4Main.allJava
-}
-
-opensaml3Test {
-	useJUnitPlatform()
-}
-
-opensaml4Test {
-	useJUnitPlatform()
-}

+ 1 - 1
saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java → saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java

@@ -134,7 +134,7 @@ import org.springframework.util.StringUtils;
  * @see <a href=
  * "https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=38">SAML 2
  * StatusResponse</a>
- * @see <a href="https://wiki.shibboleth.net/confluence/display/OS30/Home">OpenSAML 3</a>
+ * @see <a href="https://shibboleth.atlassian.net/wiki/spaces/OSAML/overview">OpenSAML</a>
  */
 public final class OpenSaml4AuthenticationProvider implements AuthenticationProvider {
 

+ 0 - 0
saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolver.java → saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolver.java


+ 0 - 0
saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolver.java → saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolver.java


+ 0 - 0
saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java → saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java


+ 0 - 864
saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java

@@ -1,864 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.saml2.provider.service.authentication;
-
-import java.io.ByteArrayInputStream;
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-
-import javax.annotation.Nonnull;
-import javax.xml.namespace.QName;
-
-import net.shibboleth.utilities.java.support.xml.ParserPool;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.opensaml.core.config.ConfigurationService;
-import org.opensaml.core.xml.XMLObject;
-import org.opensaml.core.xml.config.XMLObjectProviderRegistry;
-import org.opensaml.core.xml.schema.XSAny;
-import org.opensaml.core.xml.schema.XSBoolean;
-import org.opensaml.core.xml.schema.XSBooleanValue;
-import org.opensaml.core.xml.schema.XSDateTime;
-import org.opensaml.core.xml.schema.XSInteger;
-import org.opensaml.core.xml.schema.XSString;
-import org.opensaml.core.xml.schema.XSURI;
-import org.opensaml.saml.common.assertion.AssertionValidationException;
-import org.opensaml.saml.common.assertion.ValidationContext;
-import org.opensaml.saml.common.assertion.ValidationResult;
-import org.opensaml.saml.saml2.assertion.ConditionValidator;
-import org.opensaml.saml.saml2.assertion.SAML20AssertionValidator;
-import org.opensaml.saml.saml2.assertion.SAML2AssertionValidationParameters;
-import org.opensaml.saml.saml2.assertion.StatementValidator;
-import org.opensaml.saml.saml2.assertion.SubjectConfirmationValidator;
-import org.opensaml.saml.saml2.assertion.impl.AudienceRestrictionConditionValidator;
-import org.opensaml.saml.saml2.assertion.impl.BearerSubjectConfirmationValidator;
-import org.opensaml.saml.saml2.assertion.impl.DelegationRestrictionConditionValidator;
-import org.opensaml.saml.saml2.core.Assertion;
-import org.opensaml.saml.saml2.core.Attribute;
-import org.opensaml.saml.saml2.core.AttributeStatement;
-import org.opensaml.saml.saml2.core.Condition;
-import org.opensaml.saml.saml2.core.EncryptedAssertion;
-import org.opensaml.saml.saml2.core.OneTimeUse;
-import org.opensaml.saml.saml2.core.Response;
-import org.opensaml.saml.saml2.core.StatusCode;
-import org.opensaml.saml.saml2.core.SubjectConfirmation;
-import org.opensaml.saml.saml2.core.impl.ResponseUnmarshaller;
-import org.opensaml.saml.saml2.encryption.Decrypter;
-import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator;
-import org.opensaml.xmlsec.signature.support.SignaturePrevalidator;
-import org.opensaml.xmlsec.signature.support.SignatureTrustEngine;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.core.log.LogMessage;
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-import org.springframework.security.authentication.AuthenticationProvider;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-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.saml2.Saml2Exception;
-import org.springframework.security.saml2.core.OpenSamlInitializationService;
-import org.springframework.security.saml2.core.Saml2Error;
-import org.springframework.security.saml2.core.Saml2ErrorCodes;
-import org.springframework.security.saml2.core.Saml2ResponseValidatorResult;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
-import org.springframework.util.Assert;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
-/**
- * Implementation of {@link AuthenticationProvider} for SAML authentications when
- * receiving a {@code Response} object containing an {@code Assertion}. This
- * implementation uses the {@code OpenSAML 3} library.
- *
- * <p>
- * The {@link OpenSamlAuthenticationProvider} supports {@link Saml2AuthenticationToken}
- * objects that contain a SAML response in its decoded XML format
- * {@link Saml2AuthenticationToken#getSaml2Response()} along with the information about
- * the asserting party, the identity provider (IDP), as well as the relying party, the
- * service provider (SP, this application).
- * <p>
- * The {@link Saml2AuthenticationToken} will be processed into a SAML Response object. The
- * SAML response object can be signed. If the Response is signed, a signature will not be
- * required on the assertion.
- * <p>
- * While a response object can contain a list of assertion, this provider will only
- * leverage the first valid assertion for the purpose of authentication. Assertions that
- * do not pass validation will be ignored. If no valid assertions are found a
- * {@link Saml2AuthenticationException} is thrown.
- * <p>
- * This provider supports two types of encrypted SAML elements
- * <ul>
- * <li><a href=
- * "https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=17">EncryptedAssertion</a></li>
- * <li><a href=
- * "https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=14">EncryptedID</a></li>
- * </ul>
- * If the assertion is encrypted, then signature validation on the assertion is no longer
- * required.
- * <p>
- * This provider does not perform an X509 certificate validation on the configured
- * asserting party, IDP, verification certificates.
- *
- * @author Ryan Cassar
- * @since 5.2
- * @see <a href=
- * "https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=38">SAML 2
- * StatusResponse</a>
- * @see <a href="https://wiki.shibboleth.net/confluence/display/OS30/Home">OpenSAML 3</a>
- * @deprecated Because OpenSAML 3 has reached End-of-Life, please update to
- * {@code OpenSaml4AuthenticationProvider}
- */
-public final class OpenSamlAuthenticationProvider implements AuthenticationProvider {
-
-	static {
-		OpenSamlInitializationService.initialize();
-	}
-
-	private static Log logger = LogFactory.getLog(OpenSamlAuthenticationProvider.class);
-
-	private final XMLObjectProviderRegistry registry;
-
-	private final ResponseUnmarshaller responseUnmarshaller;
-
-	private final ParserPool parserPool;
-
-	private Converter<Assertion, Collection<? extends GrantedAuthority>> authoritiesExtractor = ((a) -> Collections
-			.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
-
-	private GrantedAuthoritiesMapper authoritiesMapper = ((a) -> a);
-
-	private Duration responseTimeValidationSkew = Duration.ofMinutes(5);
-
-	private Converter<ResponseToken, Saml2ResponseValidatorResult> responseSignatureValidator = createDefaultResponseSignatureValidator();
-
-	private Consumer<ResponseToken> responseElementsDecrypter = createDefaultResponseElementsDecrypter();
-
-	private Converter<ResponseToken, Saml2ResponseValidatorResult> responseValidator = createDefaultResponseValidator();
-
-	private Converter<AssertionToken, Saml2ResponseValidatorResult> assertionSignatureValidator = createDefaultAssertionSignatureValidator();
-
-	private Consumer<AssertionToken> assertionElementsDecrypter = createDefaultAssertionElementsDecrypter();
-
-	private Converter<AssertionToken, Saml2ResponseValidatorResult> assertionValidator = createCompatibleAssertionValidator();
-
-	private Converter<ResponseToken, ? extends AbstractAuthenticationToken> responseAuthenticationConverter = createCompatibleResponseAuthenticationConverter();
-
-	/**
-	 * Creates an {@link OpenSamlAuthenticationProvider}
-	 */
-	public OpenSamlAuthenticationProvider() {
-		this.registry = ConfigurationService.get(XMLObjectProviderRegistry.class);
-		this.responseUnmarshaller = (ResponseUnmarshaller) this.registry.getUnmarshallerFactory()
-				.getUnmarshaller(Response.DEFAULT_ELEMENT_NAME);
-		this.parserPool = this.registry.getParserPool();
-	}
-
-	/**
-	 * Set the {@link Consumer} strategy to use for decrypting elements of a validated
-	 * {@link Response}. The default strategy decrypts all {@link EncryptedAssertion}s
-	 * using OpenSAML's {@link Decrypter}, adding the results to
-	 * {@link Response#getAssertions()}.
-	 *
-	 * You can use this method to configure the {@link Decrypter} instance like so:
-	 *
-	 * <pre>
-	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-	 *	provider.setResponseElementsDecrypter((responseToken) -&gt; {
-	 *	    DecrypterParameters parameters = new DecrypterParameters();
-	 *	    // ... set parameters as needed
-	 *	    Decrypter decrypter = new Decrypter(parameters);
-	 *		Response response = responseToken.getResponse();
-	 *  	EncryptedAssertion encrypted = response.getEncryptedAssertions().get(0);
-	 *  	try {
-	 *  		Assertion assertion = decrypter.decrypt(encrypted);
-	 *  		response.getAssertions().add(assertion);
-	 *  	} catch (Exception e) {
-	 *  	 	throw new Saml2AuthenticationException(...);
-	 *  	}
-	 *	});
-	 * </pre>
-	 *
-	 * Or, in the event that you have your own custom decryption interface, the same
-	 * pattern applies:
-	 *
-	 * <pre>
-	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-	 *	Converter&lt;EncryptedAssertion, Assertion&gt; myService = ...
-	 *	provider.setResponseDecrypter((responseToken) -&gt; {
-	 *	   Response response = responseToken.getResponse();
-	 *	   response.getEncryptedAssertions().stream()
-	 *	   		.map(service::decrypt).forEach(response.getAssertions()::add);
-	 *	});
-	 * </pre>
-	 *
-	 * This is valuable when using an external service to perform the decryption.
-	 * @param responseElementsDecrypter the {@link Consumer} for decrypting response
-	 * elements
-	 * @since 5.5
-	 */
-	public void setResponseElementsDecrypter(Consumer<ResponseToken> responseElementsDecrypter) {
-		Assert.notNull(responseElementsDecrypter, "responseElementsDecrypter cannot be null");
-		this.responseElementsDecrypter = responseElementsDecrypter;
-	}
-
-	/**
-	 * Set the {@link Converter} to use for validating each {@link Assertion} in the SAML
-	 * 2.0 Response.
-	 *
-	 * You can still invoke the default validator by delgating to
-	 * {@link #createAssertionValidator}, like so:
-	 *
-	 * <pre>
-	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-	 *  provider.setAssertionValidator(assertionToken -&gt; {
-	 *		Saml2ResponseValidatorResult result = createDefaultAssertionValidator()
-	 *			.convert(assertionToken)
-	 *		return result.concat(myCustomValidator.convert(assertionToken));
-	 *  });
-	 * </pre>
-	 *
-	 * You can also use this method to configure the provider to use a different
-	 * {@link ValidationContext} from the default, like so:
-	 *
-	 * <pre>
-	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-	 *	provider.setAssertionValidator(
-	 *		createDefaultAssertionValidator(assertionToken -&gt; {
-	 *			Map&lt;String, Object&gt; params = new HashMap&lt;&gt;();
-	 *			params.put(CLOCK_SKEW, 2 * 60 * 1000);
-	 *			// other parameters
-	 *			return new ValidationContext(params);
-	 *		}));
-	 * </pre>
-	 *
-	 * Consider taking a look at {@link #createValidationContext} to see how it constructs
-	 * a {@link ValidationContext}.
-	 *
-	 * It is not necessary to delegate to the default validator. You can safely replace it
-	 * entirely with your own. Note that signature verification is performed as a separate
-	 * step from this validator.
-	 *
-	 * This method takes precedence over {@link #setResponseTimeValidationSkew}.
-	 * @param assertionValidator the strategy for validating a given assertion
-	 * @since 5.4
-	 */
-	public void setAssertionValidator(Converter<AssertionToken, Saml2ResponseValidatorResult> assertionValidator) {
-		Assert.notNull(assertionValidator, "assertionValidator cannot be null");
-		this.assertionValidator = assertionValidator;
-	}
-
-	/**
-	 * Set the {@link Consumer} strategy to use for decrypting elements of a validated
-	 * {@link Assertion}.
-	 *
-	 * You can use this method to configure the {@link Decrypter} used like so:
-	 *
-	 * <pre>
-	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-	 *	provider.setResponseDecrypter((assertionToken) -&gt; {
-	 *	    DecrypterParameters parameters = new DecrypterParameters();
-	 *	    // ... set parameters as needed
-	 *	    Decrypter decrypter = new Decrypter(parameters);
-	 *		Assertion assertion = assertionToken.getAssertion();
-	 *  	EncryptedID encrypted = assertion.getSubject().getEncryptedID();
-	 *  	try {
-	 *  		NameID name = decrypter.decrypt(encrypted);
-	 *  		assertion.getSubject().setNameID(name);
-	 *  	} catch (Exception e) {
-	 *  	 	throw new Saml2AuthenticationException(...);
-	 *  	}
-	 *	});
-	 * </pre>
-	 *
-	 * Or, in the event that you have your own custom interface, the same pattern applies:
-	 *
-	 * <pre>
-	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-	 *	MyDecryptionService myService = ...
-	 *	provider.setResponseDecrypter((responseToken) -&gt; {
-	 *	   	Assertion assertion = assertionToken.getAssertion();
-	 *	   	EncryptedID encrypted = assertion.getSubject().getEncryptedID();
-	 *		NameID name = myService.decrypt(encrypted);
-	 *		assertion.getSubject().setNameID(name);
-	 *	});
-	 * </pre>
-	 * @param assertionDecrypter the {@link Consumer} for decrypting assertion elements
-	 * @since 5.5
-	 */
-	public void setAssertionElementsDecrypter(Consumer<AssertionToken> assertionDecrypter) {
-		Assert.notNull(assertionDecrypter, "assertionDecrypter cannot be null");
-		this.assertionElementsDecrypter = assertionDecrypter;
-	}
-
-	/**
-	 * Set the {@link Converter} to use for converting a validated {@link Response} into
-	 * an {@link AbstractAuthenticationToken}.
-	 *
-	 * You can delegate to the default behavior by calling
-	 * {@link #createDefaultResponseAuthenticationConverter()} like so:
-	 *
-	 * <pre>
-	 *	OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-	 * 	Converter&lt;ResponseToken, Saml2Authentication&gt; authenticationConverter =
-	 * 			createDefaultResponseAuthenticationConverter();
-	 *	provider.setResponseAuthenticationConverter(responseToken -&gt; {
-	 *		Saml2Authentication authentication = authenticationConverter.convert(responseToken);
-	 *		User user = myUserRepository.findByUsername(authentication.getName());
-	 *		return new MyAuthentication(authentication, user);
-	 *	});
-	 * </pre>
-	 *
-	 * This method takes precedence over {@link #setAuthoritiesExtractor(Converter)} and
-	 * {@link #setAuthoritiesMapper(GrantedAuthoritiesMapper)}.
-	 * @param responseAuthenticationConverter the {@link Converter} to use
-	 * @since 5.4
-	 */
-	public void setResponseAuthenticationConverter(
-			Converter<ResponseToken, ? extends AbstractAuthenticationToken> responseAuthenticationConverter) {
-		Assert.notNull(responseAuthenticationConverter, "responseAuthenticationConverter cannot be null");
-		this.responseAuthenticationConverter = responseAuthenticationConverter;
-	}
-
-	/**
-	 * Sets the {@link Converter} used for extracting assertion attributes that can be
-	 * mapped to authorities.
-	 * @param authoritiesExtractor the {@code Converter} used for mapping the assertion
-	 * attributes to authorities
-	 * @deprecated Use {@link #setResponseAuthenticationConverter(Converter)} instead
-	 */
-	public void setAuthoritiesExtractor(
-			Converter<Assertion, Collection<? extends GrantedAuthority>> authoritiesExtractor) {
-		Assert.notNull(authoritiesExtractor, "authoritiesExtractor cannot be null");
-		this.authoritiesExtractor = authoritiesExtractor;
-	}
-
-	/**
-	 * Sets the {@link GrantedAuthoritiesMapper} used for mapping assertion attributes to
-	 * a new set of authorities which will be associated to the
-	 * {@link Saml2Authentication}. Note: This implementation is only retrieving
-	 * @param authoritiesMapper the {@link GrantedAuthoritiesMapper} used for mapping the
-	 * user's authorities
-	 * @deprecated Use {@link #setResponseAuthenticationConverter(Converter)} instead
-	 */
-	public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
-		Assert.notNull(authoritiesMapper, "authoritiesMapper cannot be null");
-		this.authoritiesMapper = authoritiesMapper;
-	}
-
-	/**
-	 * Sets the duration for how much time skew an assertion may tolerate during
-	 * timestamp, NotOnOrBefore and NotOnOrAfter, validation.
-	 * @param responseTimeValidationSkew duration for skew tolerance
-	 * @deprecated Use {@link #setAssertionValidator(Converter)} instead
-	 */
-	public void setResponseTimeValidationSkew(Duration responseTimeValidationSkew) {
-		this.responseTimeValidationSkew = responseTimeValidationSkew;
-	}
-
-	/**
-	 * Construct a default strategy for validating each SAML 2.0 Assertion and associated
-	 * {@link Authentication} token
-	 * @return the default assertion validator strategy
-	 * @since 5.4
-	 */
-	public static Converter<AssertionToken, Saml2ResponseValidatorResult> createDefaultAssertionValidator() {
-
-		return createAssertionValidator(Saml2ErrorCodes.INVALID_ASSERTION,
-				(assertionToken) -> SAML20AssertionValidators.attributeValidator,
-				(assertionToken) -> createValidationContext(assertionToken, (params) -> {
-				}));
-	}
-
-	/**
-	 * Construct a default strategy for validating each SAML 2.0 Assertion and associated
-	 * {@link Authentication} token
-	 * @param contextConverter the conversion strategy to use to generate a
-	 * {@link ValidationContext} for each assertion being validated
-	 * @return the default assertion validator strategy
-	 * @since 5.4
-	 */
-	public static Converter<AssertionToken, Saml2ResponseValidatorResult> createDefaultAssertionValidator(
-			Converter<AssertionToken, ValidationContext> contextConverter) {
-
-		return createAssertionValidator(Saml2ErrorCodes.INVALID_ASSERTION,
-				(assertionToken) -> SAML20AssertionValidators.attributeValidator, contextConverter);
-	}
-
-	/**
-	 * Construct a default strategy for converting a SAML 2.0 Response and
-	 * {@link Authentication} token into a {@link Saml2Authentication}
-	 * @return the default response authentication converter strategy
-	 * @since 5.4
-	 */
-	public static Converter<ResponseToken, Saml2Authentication> createDefaultResponseAuthenticationConverter() {
-		return (responseToken) -> {
-			Saml2AuthenticationToken token = responseToken.token;
-			Response response = responseToken.response;
-			Assertion assertion = CollectionUtils.firstElement(response.getAssertions());
-			String username = assertion.getSubject().getNameID().getValue();
-			Map<String, List<Object>> attributes = getAssertionAttributes(assertion);
-			DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal(username, attributes);
-			String registrationId = responseToken.token.getRelyingPartyRegistration().getRegistrationId();
-			principal.setRelyingPartyRegistrationId(registrationId);
-			return new Saml2Authentication(principal, token.getSaml2Response(),
-					Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")));
-		};
-	}
-
-	/**
-	 * @param authentication the authentication request object, must be of type
-	 * {@link Saml2AuthenticationToken}
-	 * @return {@link Saml2Authentication} if the assertion is valid
-	 * @throws AuthenticationException if a validation exception occurs
-	 */
-	@Override
-	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
-		try {
-			Saml2AuthenticationToken token = (Saml2AuthenticationToken) authentication;
-			String serializedResponse = token.getSaml2Response();
-			Response response = parse(serializedResponse);
-			process(token, response);
-			return this.responseAuthenticationConverter.convert(new ResponseToken(response, token));
-		}
-		catch (Saml2AuthenticationException ex) {
-			throw ex;
-		}
-		catch (Exception ex) {
-			throw createAuthenticationException(Saml2ErrorCodes.INTERNAL_VALIDATION_ERROR, ex.getMessage(), ex);
-		}
-	}
-
-	@Override
-	public boolean supports(Class<?> authentication) {
-		return authentication != null && Saml2AuthenticationToken.class.isAssignableFrom(authentication);
-	}
-
-	private Response parse(String response) throws Saml2Exception, Saml2AuthenticationException {
-		try {
-			Document document = this.parserPool
-					.parse(new ByteArrayInputStream(response.getBytes(StandardCharsets.UTF_8)));
-			Element element = document.getDocumentElement();
-			return (Response) this.responseUnmarshaller.unmarshall(element);
-		}
-		catch (Exception ex) {
-			throw createAuthenticationException(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, ex.getMessage(), ex);
-		}
-	}
-
-	private void process(Saml2AuthenticationToken token, Response response) {
-		String issuer = response.getIssuer().getValue();
-		logger.debug(LogMessage.format("Processing SAML response from %s", issuer));
-		boolean responseSigned = response.isSigned();
-
-		ResponseToken responseToken = new ResponseToken(response, token);
-		Saml2ResponseValidatorResult result = this.responseSignatureValidator.convert(responseToken);
-		if (responseSigned) {
-			this.responseElementsDecrypter.accept(responseToken);
-		}
-		result = result.concat(this.responseValidator.convert(responseToken));
-		boolean allAssertionsSigned = true;
-		for (Assertion assertion : response.getAssertions()) {
-			AssertionToken assertionToken = new AssertionToken(assertion, token);
-			result = result.concat(this.assertionSignatureValidator.convert(assertionToken));
-			allAssertionsSigned = allAssertionsSigned && assertion.isSigned();
-			if (responseSigned || assertion.isSigned()) {
-				this.assertionElementsDecrypter.accept(new AssertionToken(assertion, token));
-			}
-			result = result.concat(this.assertionValidator.convert(assertionToken));
-		}
-		if (!responseSigned && !allAssertionsSigned) {
-			String description = "Either the response or one of the assertions is unsigned. "
-					+ "Please either sign the response or all of the assertions.";
-			throw createAuthenticationException(Saml2ErrorCodes.INVALID_SIGNATURE, description, null);
-		}
-		Assertion firstAssertion = CollectionUtils.firstElement(response.getAssertions());
-		if (!hasName(firstAssertion)) {
-			Saml2Error error = new Saml2Error(Saml2ErrorCodes.SUBJECT_NOT_FOUND,
-					"Assertion [" + firstAssertion.getID() + "] is missing a subject");
-			result = result.concat(error);
-		}
-
-		if (result.hasErrors()) {
-			Collection<Saml2Error> errors = result.getErrors();
-			if (logger.isTraceEnabled()) {
-				logger.debug("Found " + errors.size() + " validation errors in SAML response [" + response.getID()
-						+ "]: " + errors);
-			}
-			else if (logger.isDebugEnabled()) {
-				logger.debug(
-						"Found " + errors.size() + " validation errors in SAML response [" + response.getID() + "]");
-			}
-			Saml2Error first = errors.iterator().next();
-			throw createAuthenticationException(first.getErrorCode(), first.getDescription(), null);
-		}
-		else {
-			if (logger.isDebugEnabled()) {
-				logger.debug("Successfully processed SAML Response [" + response.getID() + "]");
-			}
-		}
-	}
-
-	private Converter<ResponseToken, Saml2ResponseValidatorResult> createDefaultResponseSignatureValidator() {
-		return (responseToken) -> {
-			Response response = responseToken.getResponse();
-			RelyingPartyRegistration registration = responseToken.getToken().getRelyingPartyRegistration();
-			if (response.isSigned()) {
-				return OpenSamlVerificationUtils.verifySignature(response, registration).post(response.getSignature());
-			}
-			return Saml2ResponseValidatorResult.success();
-		};
-	}
-
-	private Consumer<ResponseToken> createDefaultResponseElementsDecrypter() {
-		return (responseToken) -> {
-			Response response = responseToken.getResponse();
-			RelyingPartyRegistration registration = responseToken.getToken().getRelyingPartyRegistration();
-			try {
-				OpenSamlDecryptionUtils.decryptResponseElements(response, registration);
-			}
-			catch (Saml2Exception ex) {
-				throw createAuthenticationException(Saml2ErrorCodes.DECRYPTION_ERROR, ex.getMessage(), ex);
-			}
-		};
-	}
-
-	private Converter<ResponseToken, Saml2ResponseValidatorResult> createDefaultResponseValidator() {
-		return (responseToken) -> {
-			Response response = responseToken.getResponse();
-			Saml2AuthenticationToken token = responseToken.getToken();
-			Saml2ResponseValidatorResult result = Saml2ResponseValidatorResult.success();
-			String statusCode = getStatusCode(response);
-			if (!StatusCode.SUCCESS.equals(statusCode)) {
-				String message = String.format("Invalid status [%s] for SAML response [%s]", statusCode,
-						response.getID());
-				result = result.concat(new Saml2Error(Saml2ErrorCodes.INVALID_RESPONSE, message));
-			}
-			String issuer = response.getIssuer().getValue();
-			String destination = response.getDestination();
-			String location = token.getRelyingPartyRegistration().getAssertionConsumerServiceLocation();
-			if (StringUtils.hasText(destination) && !destination.equals(location)) {
-				String message = "Invalid destination [" + destination + "] for SAML response [" + response.getID()
-						+ "]";
-				result = result.concat(new Saml2Error(Saml2ErrorCodes.INVALID_DESTINATION, message));
-			}
-			String assertingPartyEntityId = token.getRelyingPartyRegistration().getAssertingPartyDetails()
-					.getEntityId();
-			if (!StringUtils.hasText(issuer) || !issuer.equals(assertingPartyEntityId)) {
-				String message = String.format("Invalid issuer [%s] for SAML response [%s]", issuer, response.getID());
-				result = result.concat(new Saml2Error(Saml2ErrorCodes.INVALID_ISSUER, message));
-			}
-			if (response.getAssertions().isEmpty()) {
-				throw createAuthenticationException(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA,
-						"No assertions found in response.", null);
-			}
-			return result;
-		};
-	}
-
-	private String getStatusCode(Response response) {
-		if (response.getStatus() == null) {
-			return StatusCode.SUCCESS;
-		}
-		if (response.getStatus().getStatusCode() == null) {
-			return StatusCode.SUCCESS;
-		}
-		return response.getStatus().getStatusCode().getValue();
-	}
-
-	private Converter<AssertionToken, Saml2ResponseValidatorResult> createDefaultAssertionSignatureValidator() {
-		return createAssertionValidator(Saml2ErrorCodes.INVALID_SIGNATURE, (assertionToken) -> {
-			RelyingPartyRegistration registration = assertionToken.getToken().getRelyingPartyRegistration();
-			SignatureTrustEngine engine = OpenSamlVerificationUtils.trustEngine(registration);
-			return SAML20AssertionValidators.createSignatureValidator(engine);
-		}, (assertionToken) -> new ValidationContext(
-				Collections.singletonMap(SAML2AssertionValidationParameters.SIGNATURE_REQUIRED, false)));
-	}
-
-	private Consumer<AssertionToken> createDefaultAssertionElementsDecrypter() {
-		return (assertionToken) -> {
-			Assertion assertion = assertionToken.getAssertion();
-			RelyingPartyRegistration registration = assertionToken.getToken().getRelyingPartyRegistration();
-			try {
-				OpenSamlDecryptionUtils.decryptAssertionElements(assertion, registration);
-			}
-			catch (Saml2Exception ex) {
-				throw createAuthenticationException(Saml2ErrorCodes.DECRYPTION_ERROR, ex.getMessage(), ex);
-			}
-		};
-	}
-
-	private Converter<AssertionToken, Saml2ResponseValidatorResult> createCompatibleAssertionValidator() {
-		return createAssertionValidator(Saml2ErrorCodes.INVALID_ASSERTION,
-				(assertionToken) -> SAML20AssertionValidators.attributeValidator,
-				(assertionToken) -> createValidationContext(assertionToken,
-						(params) -> params.put(SAML2AssertionValidationParameters.CLOCK_SKEW,
-								this.responseTimeValidationSkew.toMillis())));
-	}
-
-	private Converter<ResponseToken, Saml2Authentication> createCompatibleResponseAuthenticationConverter() {
-		return (responseToken) -> {
-			Response response = responseToken.response;
-			Saml2AuthenticationToken token = responseToken.token;
-			Assertion assertion = CollectionUtils.firstElement(response.getAssertions());
-			String username = assertion.getSubject().getNameID().getValue();
-			Map<String, List<Object>> attributes = getAssertionAttributes(assertion);
-			DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal(username, attributes);
-			String registrationId = responseToken.token.getRelyingPartyRegistration().getRegistrationId();
-			principal.setRelyingPartyRegistrationId(registrationId);
-			return new Saml2Authentication(principal, token.getSaml2Response(),
-					this.authoritiesMapper.mapAuthorities(getAssertionAuthorities(assertion)));
-		};
-	}
-
-	private Collection<? extends GrantedAuthority> getAssertionAuthorities(Assertion assertion) {
-		return this.authoritiesExtractor.convert(assertion);
-	}
-
-	private boolean hasName(Assertion assertion) {
-		if (assertion == null) {
-			return false;
-		}
-		if (assertion.getSubject() == null) {
-			return false;
-		}
-		if (assertion.getSubject().getNameID() == null) {
-			return false;
-		}
-		return assertion.getSubject().getNameID().getValue() != null;
-	}
-
-	private static Map<String, List<Object>> getAssertionAttributes(Assertion assertion) {
-		Map<String, List<Object>> attributeMap = new LinkedHashMap<>();
-		for (AttributeStatement attributeStatement : assertion.getAttributeStatements()) {
-			for (Attribute attribute : attributeStatement.getAttributes()) {
-				List<Object> attributeValues = new ArrayList<>();
-				for (XMLObject xmlObject : attribute.getAttributeValues()) {
-					Object attributeValue = getXmlObjectValue(xmlObject);
-					if (attributeValue != null) {
-						attributeValues.add(attributeValue);
-					}
-				}
-				attributeMap.put(attribute.getName(), attributeValues);
-			}
-		}
-		return attributeMap;
-	}
-
-	private static Object getXmlObjectValue(XMLObject xmlObject) {
-		if (xmlObject instanceof XSAny) {
-			return ((XSAny) xmlObject).getTextContent();
-		}
-		if (xmlObject instanceof XSString) {
-			return ((XSString) xmlObject).getValue();
-		}
-		if (xmlObject instanceof XSInteger) {
-			return ((XSInteger) xmlObject).getValue();
-		}
-		if (xmlObject instanceof XSURI) {
-			return ((XSURI) xmlObject).getValue();
-		}
-		if (xmlObject instanceof XSBoolean) {
-			XSBooleanValue xsBooleanValue = ((XSBoolean) xmlObject).getValue();
-			return (xsBooleanValue != null) ? xsBooleanValue.getValue() : null;
-		}
-		if (xmlObject instanceof XSDateTime) {
-			return Instant.ofEpochMilli(((XSDateTime) xmlObject).getValue().getMillis());
-		}
-		return null;
-	}
-
-	private static Saml2AuthenticationException createAuthenticationException(String code, String message,
-			Exception cause) {
-		return new Saml2AuthenticationException(new Saml2Error(code, message), cause);
-	}
-
-	private static Converter<AssertionToken, Saml2ResponseValidatorResult> createAssertionValidator(String errorCode,
-			Converter<AssertionToken, SAML20AssertionValidator> validatorConverter,
-			Converter<AssertionToken, ValidationContext> contextConverter) {
-
-		return (assertionToken) -> {
-			Assertion assertion = assertionToken.assertion;
-			SAML20AssertionValidator validator = validatorConverter.convert(assertionToken);
-			ValidationContext context = contextConverter.convert(assertionToken);
-			try {
-				ValidationResult result = validator.validate(assertion, context);
-				if (result == ValidationResult.VALID) {
-					return Saml2ResponseValidatorResult.success();
-				}
-			}
-			catch (Exception ex) {
-				String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(),
-						((Response) assertion.getParent()).getID(), ex.getMessage());
-				return Saml2ResponseValidatorResult.failure(new Saml2Error(errorCode, message));
-			}
-			String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(),
-					((Response) assertion.getParent()).getID(), context.getValidationFailureMessage());
-			return Saml2ResponseValidatorResult.failure(new Saml2Error(errorCode, message));
-		};
-	}
-
-	private static ValidationContext createValidationContext(AssertionToken assertionToken,
-			Consumer<Map<String, Object>> paramsConsumer) {
-		String audience = assertionToken.token.getRelyingPartyRegistration().getEntityId();
-		String recipient = assertionToken.token.getRelyingPartyRegistration().getAssertionConsumerServiceLocation();
-		Map<String, Object> params = new HashMap<>();
-		params.put(SAML2AssertionValidationParameters.COND_VALID_AUDIENCES, Collections.singleton(audience));
-		params.put(SAML2AssertionValidationParameters.SC_VALID_RECIPIENTS, Collections.singleton(recipient));
-		paramsConsumer.accept(params);
-		return new ValidationContext(params);
-	}
-
-	private static class SAML20AssertionValidators {
-
-		private static final Collection<ConditionValidator> conditions = new ArrayList<>();
-
-		private static final Collection<SubjectConfirmationValidator> subjects = new ArrayList<>();
-
-		private static final Collection<StatementValidator> statements = new ArrayList<>();
-
-		private static final SignaturePrevalidator validator = new SAMLSignatureProfileValidator();
-
-		static {
-			conditions.add(new AudienceRestrictionConditionValidator());
-			conditions.add(new DelegationRestrictionConditionValidator());
-			conditions.add(new ConditionValidator() {
-				@Nonnull
-				@Override
-				public QName getServicedCondition() {
-					return OneTimeUse.DEFAULT_ELEMENT_NAME;
-				}
-
-				@Nonnull
-				@Override
-				public ValidationResult validate(Condition condition, Assertion assertion, ValidationContext context) {
-					// applications should validate their own OneTimeUse conditions
-					return ValidationResult.VALID;
-				}
-			});
-			subjects.add(new BearerSubjectConfirmationValidator() {
-				@Override
-				protected ValidationResult validateAddress(SubjectConfirmation confirmation, Assertion assertion,
-						ValidationContext context) throws AssertionValidationException {
-					// applications should validate their own addresses - gh-7514
-					return ValidationResult.VALID;
-				}
-			});
-		}
-
-		private static final SAML20AssertionValidator attributeValidator = new SAML20AssertionValidator(conditions,
-				subjects, statements, null, null) {
-			@Nonnull
-			@Override
-			protected ValidationResult validateSignature(Assertion token, ValidationContext context) {
-				return ValidationResult.VALID;
-			}
-		};
-
-		static SAML20AssertionValidator createSignatureValidator(SignatureTrustEngine engine) {
-			return new SAML20AssertionValidator(new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), engine,
-					validator) {
-				@Nonnull
-				@Override
-				protected ValidationResult validateConditions(Assertion assertion, ValidationContext context) {
-					return ValidationResult.VALID;
-				}
-
-				@Nonnull
-				@Override
-				protected ValidationResult validateSubjectConfirmation(Assertion assertion, ValidationContext context) {
-					return ValidationResult.VALID;
-				}
-
-				@Nonnull
-				@Override
-				protected ValidationResult validateStatements(Assertion assertion, ValidationContext context) {
-					return ValidationResult.VALID;
-				}
-			};
-
-		}
-
-	}
-
-	/**
-	 * A tuple containing an OpenSAML {@link Response} and its associated authentication
-	 * token.
-	 *
-	 * @since 5.4
-	 */
-	public static class ResponseToken {
-
-		private final Saml2AuthenticationToken token;
-
-		private final Response response;
-
-		ResponseToken(Response response, Saml2AuthenticationToken token) {
-			this.token = token;
-			this.response = response;
-		}
-
-		public Response getResponse() {
-			return this.response;
-		}
-
-		public Saml2AuthenticationToken getToken() {
-			return this.token;
-		}
-
-	}
-
-	/**
-	 * A tuple containing an OpenSAML {@link Assertion} and its associated authentication
-	 * token.
-	 *
-	 * @since 5.4
-	 */
-	public static class AssertionToken {
-
-		private final Saml2AuthenticationToken token;
-
-		private final Assertion assertion;
-
-		AssertionToken(Assertion assertion, Saml2AuthenticationToken token) {
-			this.token = token;
-			this.assertion = assertion;
-		}
-
-		public Assertion getAssertion() {
-			return this.assertion;
-		}
-
-		public Saml2AuthenticationToken getToken() {
-			return this.token;
-		}
-
-	}
-
-}

+ 0 - 112
saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml3AuthenticationRequestResolver.java

@@ -1,112 +0,0 @@
-/*
- * Copyright 2002-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.saml2.provider.service.web.authentication;
-
-import java.time.Clock;
-import java.util.function.Consumer;
-
-import jakarta.servlet.http.HttpServletRequest;
-import org.joda.time.DateTime;
-import org.opensaml.saml.saml2.core.AuthnRequest;
-import org.opensaml.saml.saml2.core.LogoutRequest;
-
-import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
-import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
-import org.springframework.util.Assert;
-
-/**
- * A strategy for resolving a SAML 2.0 Authentication Request from the
- * {@link HttpServletRequest} using OpenSAML.
- *
- * @author Josh Cummings
- * @since 5.7
- * @deprecated OpenSAML 3 has reached end-of-life so this version is no longer recommended
- */
-@Deprecated
-public final class OpenSaml3AuthenticationRequestResolver implements Saml2AuthenticationRequestResolver {
-
-	private final OpenSamlAuthenticationRequestResolver authnRequestResolver;
-
-	private Consumer<AuthnRequestContext> contextConsumer = (parameters) -> {
-	};
-
-	private Clock clock = Clock.systemUTC();
-
-	/**
-	 * Construct a {@link OpenSaml3AuthenticationRequestResolver}
-	 */
-	public OpenSaml3AuthenticationRequestResolver(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
-		this.authnRequestResolver = new OpenSamlAuthenticationRequestResolver(relyingPartyRegistrationResolver);
-	}
-
-	@Override
-	public <T extends AbstractSaml2AuthenticationRequest> T resolve(HttpServletRequest request) {
-		return this.authnRequestResolver.resolve(request, (registration, authnRequest) -> {
-			authnRequest.setIssueInstant(new DateTime(this.clock.millis()));
-			this.contextConsumer.accept(new AuthnRequestContext(request, registration, authnRequest));
-		});
-	}
-
-	/**
-	 * Set a {@link Consumer} for modifying the OpenSAML {@link LogoutRequest}
-	 * @param contextConsumer a consumer that accepts an {@link AuthnRequestContext}
-	 */
-	public void setAuthnRequestCustomizer(Consumer<AuthnRequestContext> contextConsumer) {
-		Assert.notNull(contextConsumer, "contextConsumer cannot be null");
-		this.contextConsumer = contextConsumer;
-	}
-
-	/**
-	 * Use this {@link Clock} for generating the issued {@link DateTime}
-	 * @param clock the {@link Clock} to use
-	 */
-	public void setClock(Clock clock) {
-		Assert.notNull(clock, "clock must not be null");
-		this.clock = clock;
-	}
-
-	public static final class AuthnRequestContext {
-
-		private final HttpServletRequest request;
-
-		private final RelyingPartyRegistration registration;
-
-		private final AuthnRequest authnRequest;
-
-		public AuthnRequestContext(HttpServletRequest request, RelyingPartyRegistration registration,
-				AuthnRequest authnRequest) {
-			this.request = request;
-			this.registration = registration;
-			this.authnRequest = authnRequest;
-		}
-
-		public HttpServletRequest getRequest() {
-			return this.request;
-		}
-
-		public RelyingPartyRegistration getRelyingPartyRegistration() {
-			return this.registration;
-		}
-
-		public AuthnRequest getAuthnRequest() {
-			return this.authnRequest;
-		}
-
-	}
-
-}

+ 0 - 124
saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolver.java

@@ -1,124 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.saml2.provider.service.web.authentication.logout;
-
-import java.time.Clock;
-import java.util.function.Consumer;
-
-import jakarta.servlet.http.HttpServletRequest;
-import org.joda.time.DateTime;
-import org.opensaml.saml.saml2.core.LogoutRequest;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
-import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
-import org.springframework.util.Assert;
-
-/**
- * A {@link Saml2LogoutRequestResolver} for resolving SAML 2.0 Logout Requests with
- * OpenSAML 3
- *
- * @author Josh Cummings
- * @since 5.6
- * @deprecated Because OpenSAML 3 has reached End-of-Life, please update to
- * {@code OpenSaml4LogoutRequestResolver}
- */
-public final class OpenSaml3LogoutRequestResolver implements Saml2LogoutRequestResolver {
-
-	private final OpenSamlLogoutRequestResolver logoutRequestResolver;
-
-	private Consumer<LogoutRequestParameters> parametersConsumer = (parameters) -> {
-	};
-
-	private Clock clock = Clock.systemUTC();
-
-	/**
-	 * Construct a {@link OpenSaml3LogoutRequestResolver}
-	 */
-	public OpenSaml3LogoutRequestResolver(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
-		this.logoutRequestResolver = new OpenSamlLogoutRequestResolver(relyingPartyRegistrationResolver);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Saml2LogoutRequest resolve(HttpServletRequest request, Authentication authentication) {
-		return this.logoutRequestResolver.resolve(request, authentication, (registration, logoutRequest) -> {
-			logoutRequest.setIssueInstant(new DateTime(this.clock.millis()));
-			this.parametersConsumer
-					.accept(new LogoutRequestParameters(request, registration, authentication, logoutRequest));
-		});
-	}
-
-	/**
-	 * Set a {@link Consumer} for modifying the OpenSAML {@link LogoutRequest}
-	 * @param parametersConsumer a consumer that accepts an
-	 * {@link LogoutRequestParameters}
-	 */
-	public void setParametersConsumer(Consumer<LogoutRequestParameters> parametersConsumer) {
-		Assert.notNull(parametersConsumer, "parametersConsumer cannot be null");
-		this.parametersConsumer = parametersConsumer;
-	}
-
-	/**
-	 * Use this {@link Clock} for generating the issued {@link DateTime}
-	 * @param clock the {@link Clock} to use
-	 */
-	public void setClock(Clock clock) {
-		Assert.notNull(clock, "clock must not be null");
-		this.clock = clock;
-	}
-
-	public static final class LogoutRequestParameters {
-
-		private final HttpServletRequest request;
-
-		private final RelyingPartyRegistration registration;
-
-		private final Authentication authentication;
-
-		private final LogoutRequest logoutRequest;
-
-		public LogoutRequestParameters(HttpServletRequest request, RelyingPartyRegistration registration,
-				Authentication authentication, LogoutRequest logoutRequest) {
-			this.request = request;
-			this.registration = registration;
-			this.authentication = authentication;
-			this.logoutRequest = logoutRequest;
-		}
-
-		public HttpServletRequest getRequest() {
-			return this.request;
-		}
-
-		public RelyingPartyRegistration getRelyingPartyRegistration() {
-			return this.registration;
-		}
-
-		public Authentication getAuthentication() {
-			return this.authentication;
-		}
-
-		public LogoutRequest getLogoutRequest() {
-			return this.logoutRequest;
-		}
-
-	}
-
-}

+ 0 - 120
saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolver.java

@@ -1,120 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.saml2.provider.service.web.authentication.logout;
-
-import java.time.Clock;
-import java.util.function.Consumer;
-
-import jakarta.servlet.http.HttpServletRequest;
-import org.joda.time.DateTime;
-import org.opensaml.saml.saml2.core.LogoutResponse;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
-import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
-import org.springframework.util.Assert;
-
-/**
- * A {@link Saml2LogoutResponseResolver} for resolving SAML 2.0 Logout Responses with
- * OpenSAML 3
- *
- * @author Josh Cummings
- * @since 5.6
- * @deprecated Because OpenSAML 3 has reached End-of-Life, please update to
- * {@code OpenSaml4LogoutResponseResolver}
- */
-public final class OpenSaml3LogoutResponseResolver implements Saml2LogoutResponseResolver {
-
-	private final OpenSamlLogoutResponseResolver logoutResponseResolver;
-
-	private Consumer<LogoutResponseParameters> parametersConsumer = (parameters) -> {
-	};
-
-	private Clock clock = Clock.systemUTC();
-
-	/**
-	 * Construct a {@link OpenSaml3LogoutResponseResolver}
-	 */
-	public OpenSaml3LogoutResponseResolver(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
-		this.logoutResponseResolver = new OpenSamlLogoutResponseResolver(relyingPartyRegistrationResolver);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Saml2LogoutResponse resolve(HttpServletRequest request, Authentication authentication) {
-		return this.logoutResponseResolver.resolve(request, authentication, (registration, logoutResponse) -> {
-			logoutResponse.setIssueInstant(new DateTime(this.clock.millis()));
-			this.parametersConsumer
-					.accept(new LogoutResponseParameters(request, registration, authentication, logoutResponse));
-		});
-	}
-
-	public void setClock(Clock clock) {
-		Assert.notNull(clock, "clock must not be null");
-		this.clock = clock;
-	}
-
-	/**
-	 * Set a {@link Consumer} for modifying the OpenSAML {@link LogoutResponse}
-	 * @param parametersConsumer a consumer that accepts an
-	 * {@link LogoutResponseParameters}
-	 */
-	public void setParametersConsumer(Consumer<LogoutResponseParameters> parametersConsumer) {
-		Assert.notNull(parametersConsumer, "parametersConsumer cannot be null");
-		this.parametersConsumer = parametersConsumer;
-	}
-
-	public static final class LogoutResponseParameters {
-
-		private final HttpServletRequest request;
-
-		private final RelyingPartyRegistration registration;
-
-		private final Authentication authentication;
-
-		private final LogoutResponse logoutResponse;
-
-		public LogoutResponseParameters(HttpServletRequest request, RelyingPartyRegistration registration,
-				Authentication authentication, LogoutResponse logoutResponse) {
-			this.request = request;
-			this.registration = registration;
-			this.authentication = authentication;
-			this.logoutResponse = logoutResponse;
-		}
-
-		public HttpServletRequest getRequest() {
-			return this.request;
-		}
-
-		public RelyingPartyRegistration getRelyingPartyRegistration() {
-			return this.registration;
-		}
-
-		public Authentication getAuthentication() {
-			return this.authentication;
-		}
-
-		public LogoutResponse getLogoutResponse() {
-			return this.logoutResponse;
-		}
-
-	}
-
-}

+ 0 - 682
saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProviderTests.java

@@ -1,682 +0,0 @@
-/*
- * Copyright 2002-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.saml2.provider.service.authentication;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.time.Instant;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-
-import javax.xml.namespace.QName;
-
-import net.shibboleth.utilities.java.support.xml.SerializeSupport;
-import org.joda.time.DateTime;
-import org.joda.time.Duration;
-import org.junit.jupiter.api.Test;
-import org.opensaml.core.xml.XMLObject;
-import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
-import org.opensaml.core.xml.io.Marshaller;
-import org.opensaml.core.xml.io.MarshallingException;
-import org.opensaml.core.xml.schema.XSDateTime;
-import org.opensaml.core.xml.schema.impl.XSDateTimeBuilder;
-import org.opensaml.saml.common.assertion.ValidationContext;
-import org.opensaml.saml.saml2.assertion.SAML2AssertionValidationParameters;
-import org.opensaml.saml.saml2.core.Assertion;
-import org.opensaml.saml.saml2.core.Attribute;
-import org.opensaml.saml.saml2.core.AttributeStatement;
-import org.opensaml.saml.saml2.core.AttributeValue;
-import org.opensaml.saml.saml2.core.Conditions;
-import org.opensaml.saml.saml2.core.EncryptedAssertion;
-import org.opensaml.saml.saml2.core.EncryptedAttribute;
-import org.opensaml.saml.saml2.core.EncryptedID;
-import org.opensaml.saml.saml2.core.NameID;
-import org.opensaml.saml.saml2.core.OneTimeUse;
-import org.opensaml.saml.saml2.core.Response;
-import org.opensaml.saml.saml2.core.StatusCode;
-import org.opensaml.saml.saml2.core.SubjectConfirmation;
-import org.opensaml.saml.saml2.core.SubjectConfirmationData;
-import org.opensaml.saml.saml2.core.impl.AttributeBuilder;
-import org.opensaml.saml.saml2.core.impl.EncryptedAssertionBuilder;
-import org.opensaml.saml.saml2.core.impl.EncryptedIDBuilder;
-import org.opensaml.saml.saml2.core.impl.NameIDBuilder;
-import org.opensaml.xmlsec.encryption.impl.EncryptedDataBuilder;
-import org.opensaml.xmlsec.signature.support.SignatureConstants;
-import org.w3c.dom.Element;
-
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.saml2.Saml2Exception;
-import org.springframework.security.saml2.core.Saml2Error;
-import org.springframework.security.saml2.core.Saml2ErrorCodes;
-import org.springframework.security.saml2.core.Saml2ResponseValidatorResult;
-import org.springframework.security.saml2.core.TestSaml2X509Credentials;
-import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider.ResponseToken;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
-import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
-import org.springframework.util.StringUtils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-/**
- * Tests for {@link OpenSamlAuthenticationProvider}
- *
- * @author Filip Hanik
- * @author Josh Cummings
- */
-public class OpenSamlAuthenticationProviderTests {
-
-	private static String DESTINATION = "https://localhost/login/saml2/sso/idp-alias";
-
-	private static String RELYING_PARTY_ENTITY_ID = "https://localhost/saml2/service-provider-metadata/idp-alias";
-
-	private static String ASSERTING_PARTY_ENTITY_ID = "https://some.idp.test/saml2/idp";
-
-	private OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-
-	private Saml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("name",
-			Collections.emptyMap());
-
-	private Saml2Authentication authentication = new Saml2Authentication(this.principal, "response",
-			Collections.emptyList());
-
-	@Test
-	public void supportsWhenSaml2AuthenticationTokenThenReturnTrue() {
-		assertThat(this.provider.supports(Saml2AuthenticationToken.class))
-				.withFailMessage(
-						OpenSamlAuthenticationProvider.class + "should support " + Saml2AuthenticationToken.class)
-				.isTrue();
-	}
-
-	@Test
-	public void supportsWhenNotSaml2AuthenticationTokenThenReturnFalse() {
-		assertThat(!this.provider.supports(Authentication.class))
-				.withFailMessage(OpenSamlAuthenticationProvider.class + "should not support " + Authentication.class)
-				.isTrue();
-	}
-
-	@Test
-	public void authenticateWhenUnknownDataClassThenThrowAuthenticationException() {
-		Assertion assertion = (Assertion) XMLObjectProviderRegistrySupport.getBuilderFactory()
-				.getBuilder(Assertion.DEFAULT_ELEMENT_NAME).buildObject(Assertion.DEFAULT_ELEMENT_NAME);
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(
-						new Saml2AuthenticationToken(verifying(registration()).build(), serialize(assertion))))
-				.satisfies(errorOf(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA));
-	}
-
-	@Test
-	public void authenticateWhenXmlErrorThenThrowAuthenticationException() {
-		Saml2AuthenticationToken token = new Saml2AuthenticationToken(verifying(registration()).build(), "invalid xml");
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA));
-	}
-
-	@Test
-	public void authenticateWhenInvalidDestinationThenThrowAuthenticationException() {
-		Response response = response(DESTINATION + "invalid", ASSERTING_PARTY_ENTITY_ID);
-		response.getAssertions().add(assertion());
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.INVALID_DESTINATION));
-	}
-
-	@Test
-	public void authenticateWhenNoAssertionsPresentThenThrowAuthenticationException() {
-		Saml2AuthenticationToken token = token();
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, "No assertions found in response."));
-	}
-
-	@Test
-	public void authenticateWhenInvalidSignatureOnAssertionThenThrowAuthenticationException() {
-		Response response = response();
-		response.getAssertions().add(assertion());
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.INVALID_SIGNATURE));
-	}
-
-	@Test
-	public void authenticateWhenOpenSAMLValidationErrorThenThrowAuthenticationException() {
-		Response response = response();
-		Assertion assertion = assertion();
-		assertion.getSubject().getSubjectConfirmations().get(0).getSubjectConfirmationData()
-				.setNotOnOrAfter(DateTime.now().minus(Duration.standardDays(3)));
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		response.getAssertions().add(assertion);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.INVALID_ASSERTION));
-	}
-
-	@Test
-	public void authenticateWhenMissingSubjectThenThrowAuthenticationException() {
-		Response response = response();
-		Assertion assertion = assertion();
-		assertion.setSubject(null);
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		response.getAssertions().add(assertion);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.SUBJECT_NOT_FOUND));
-	}
-
-	@Test
-	public void authenticateWhenUsernameMissingThenThrowAuthenticationException() {
-		Response response = response();
-		Assertion assertion = assertion();
-		assertion.getSubject().getNameID().setValue(null);
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		response.getAssertions().add(assertion);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.SUBJECT_NOT_FOUND));
-	}
-
-	@Test
-	public void authenticateWhenAssertionContainsValidationAddressThenItSucceeds() {
-		Response response = response();
-		Assertion assertion = assertion();
-		assertion.getSubject().getSubjectConfirmations()
-				.forEach((sc) -> sc.getSubjectConfirmationData().setAddress("10.10.10.10"));
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		response.getAssertions().add(assertion);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		this.provider.authenticate(token);
-	}
-
-	@Test
-	public void authenticateWhenAssertionContainsAttributesThenItSucceeds() {
-		Response response = response();
-		Assertion assertion = assertion();
-		List<AttributeStatement> attributes = attributeStatements();
-		assertion.getAttributeStatements().addAll(attributes);
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		response.getAssertions().add(assertion);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		Authentication authentication = this.provider.authenticate(token);
-		Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal();
-		Map<String, Object> expected = new LinkedHashMap<>();
-		expected.put("email", Arrays.asList("john.doe@example.com", "doe.john@example.com"));
-		expected.put("name", Collections.singletonList("John Doe"));
-		expected.put("age", Collections.singletonList(21));
-		expected.put("website", Collections.singletonList("https://johndoe.com/"));
-		expected.put("registered", Collections.singletonList(true));
-		expected.put("role", Arrays.asList("RoleTwo"));
-		Instant registeredDate = Instant.ofEpochMilli(DateTime.parse("1970-01-01T00:00:00Z").getMillis());
-		expected.put("registeredDate", Collections.singletonList(registeredDate));
-		assertThat((String) principal.getFirstAttribute("name")).isEqualTo("John Doe");
-		assertThat(principal.getAttributes()).isEqualTo(expected);
-	}
-
-	@Test
-	public void authenticateWhenEncryptedAssertionWithoutSignatureThenItFails() {
-		Response response = response();
-		EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion(),
-				TestSaml2X509Credentials.assertingPartyEncryptingCredential());
-		response.getEncryptedAssertions().add(encryptedAssertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, decrypting(registration()));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.INVALID_SIGNATURE));
-	}
-
-	@Test
-	public void authenticateWhenEncryptedAssertionWithSignatureThenItSucceeds() {
-		Response response = response();
-		Assertion assertion = TestOpenSamlObjects.signed(assertion(),
-				TestSaml2X509Credentials.assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
-		EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion,
-				TestSaml2X509Credentials.assertingPartyEncryptingCredential());
-		response.getEncryptedAssertions().add(encryptedAssertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, decrypting(verifying(registration())));
-		this.provider.authenticate(token);
-	}
-
-	@Test
-	public void authenticateWhenEncryptedAssertionWithResponseSignatureThenItSucceeds() {
-		Response response = response();
-		EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion(),
-				TestSaml2X509Credentials.assertingPartyEncryptingCredential());
-		response.getEncryptedAssertions().add(encryptedAssertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, decrypting(verifying(registration())));
-		this.provider.authenticate(token);
-	}
-
-	@Test
-	public void authenticateWhenEncryptedNameIdWithSignatureThenItSucceeds() {
-		Response response = response();
-		Assertion assertion = assertion();
-		NameID nameId = assertion.getSubject().getNameID();
-		EncryptedID encryptedID = TestOpenSamlObjects.encrypted(nameId,
-				TestSaml2X509Credentials.assertingPartyEncryptingCredential());
-		assertion.getSubject().setNameID(null);
-		assertion.getSubject().setEncryptedID(encryptedID);
-		response.getAssertions().add(assertion);
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, decrypting(verifying(registration())));
-		this.provider.authenticate(token);
-	}
-
-	@Test
-	public void authenticateWhenEncryptedAttributeThenDecrypts() {
-		Response response = response();
-		Assertion assertion = assertion();
-		EncryptedAttribute attribute = TestOpenSamlObjects.encrypted("name", "value",
-				TestSaml2X509Credentials.assertingPartyEncryptingCredential());
-		AttributeStatement statement = build(AttributeStatement.DEFAULT_ELEMENT_NAME);
-		statement.getEncryptedAttributes().add(attribute);
-		assertion.getAttributeStatements().add(statement);
-		response.getAssertions().add(assertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, decrypting(verifying(registration())));
-		Saml2Authentication authentication = (Saml2Authentication) this.provider.authenticate(token);
-		Saml2AuthenticatedPrincipal principal = (Saml2AuthenticatedPrincipal) authentication.getPrincipal();
-		assertThat(principal.getAttribute("name")).containsExactly("value");
-	}
-
-	@Test
-	public void authenticateWhenDecryptionKeysAreMissingThenThrowAuthenticationException() {
-		Response response = response();
-		EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion(),
-				TestSaml2X509Credentials.assertingPartyEncryptingCredential());
-		response.getEncryptedAssertions().add(encryptedAssertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.DECRYPTION_ERROR, "Failed to decrypt EncryptedData"));
-	}
-
-	@Test
-	public void authenticateWhenDecryptionKeysAreWrongThenThrowAuthenticationException() {
-		Response response = response();
-		EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion(),
-				TestSaml2X509Credentials.assertingPartyEncryptingCredential());
-		response.getEncryptedAssertions().add(encryptedAssertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, registration()
-				.decryptionX509Credentials((c) -> c.add(TestSaml2X509Credentials.assertingPartyPrivateCredential())));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.DECRYPTION_ERROR, "Failed to decrypt EncryptedData"));
-	}
-
-	@Test
-	public void writeObjectWhenTypeIsSaml2AuthenticationThenNoException() throws IOException {
-		Response response = response();
-		Assertion assertion = TestOpenSamlObjects.signed(assertion(),
-				TestSaml2X509Credentials.assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
-		EncryptedAssertion encryptedAssertion = TestOpenSamlObjects.encrypted(assertion,
-				TestSaml2X509Credentials.assertingPartyEncryptingCredential());
-		response.getEncryptedAssertions().add(encryptedAssertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, decrypting(verifying(registration())));
-		Saml2Authentication authentication = (Saml2Authentication) this.provider.authenticate(token);
-		// the following code will throw an exception if authentication isn't serializable
-		ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
-		ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream);
-		objectOutputStream.writeObject(authentication);
-		objectOutputStream.flush();
-	}
-
-	@Test
-	public void createDefaultAssertionValidatorWhenAssertionThenValidates() {
-		Response response = TestOpenSamlObjects.signedResponseWithOneAssertion();
-		Assertion assertion = response.getAssertions().get(0);
-		OpenSamlAuthenticationProvider.AssertionToken assertionToken = new OpenSamlAuthenticationProvider.AssertionToken(
-				assertion, token());
-		assertThat(OpenSamlAuthenticationProvider.createDefaultAssertionValidator().convert(assertionToken).hasErrors())
-				.isFalse();
-	}
-
-	@Test
-	public void authenticateWhenDelegatingToDefaultAssertionValidatorThenUses() {
-		OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-		// @formatter:off
-		provider.setAssertionValidator((assertionToken) -> OpenSamlAuthenticationProvider
-				.createDefaultAssertionValidator((token) -> new ValidationContext())
-				.convert(assertionToken)
-				.concat(new Saml2Error("wrong error", "wrong error"))
-		);
-		// @formatter:on
-		Response response = response();
-		Assertion assertion = assertion();
-		OneTimeUse oneTimeUse = build(OneTimeUse.DEFAULT_ELEMENT_NAME);
-		assertion.getConditions().getConditions().add(oneTimeUse);
-		response.getAssertions().add(assertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				ASSERTING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		// @formatter:off
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> provider.authenticate(token)).isInstanceOf(Saml2AuthenticationException.class)
-				.satisfies((error) -> assertThat(error.getSaml2Error().getErrorCode()).isEqualTo(Saml2ErrorCodes.INVALID_ASSERTION));
-		// @formatter:on
-	}
-
-	@Test
-	public void authenticateWhenCustomAssertionValidatorThenUses() {
-		Converter<OpenSamlAuthenticationProvider.AssertionToken, Saml2ResponseValidatorResult> validator = mock(
-				Converter.class);
-		OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-		// @formatter:off
-		provider.setAssertionValidator((assertionToken) -> OpenSamlAuthenticationProvider.createDefaultAssertionValidator()
-				.convert(assertionToken)
-				.concat(validator.convert(assertionToken))
-		);
-		// @formatter:on
-		Response response = response();
-		Assertion assertion = assertion();
-		response.getAssertions().add(assertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				ASSERTING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		given(validator.convert(any(OpenSamlAuthenticationProvider.AssertionToken.class)))
-				.willReturn(Saml2ResponseValidatorResult.success());
-		provider.authenticate(token);
-		verify(validator).convert(any(OpenSamlAuthenticationProvider.AssertionToken.class));
-	}
-
-	@Test
-	public void authenticateWhenDefaultConditionValidatorNotUsedThenSignatureStillChecked() {
-		OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-		provider.setAssertionValidator((assertionToken) -> Saml2ResponseValidatorResult.success());
-		Response response = response();
-		Assertion assertion = assertion();
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.relyingPartyDecryptingCredential(),
-				RELYING_PARTY_ENTITY_ID); // broken
-		// signature
-		response.getAssertions().add(assertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				ASSERTING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		// @formatter:off
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> provider.authenticate(token))
-				.satisfies((error) -> assertThat(error.getSaml2Error().getErrorCode()).isEqualTo(Saml2ErrorCodes.INVALID_SIGNATURE));
-		// @formatter:on
-	}
-
-	@Test
-	public void authenticateWhenValidationContextCustomizedThenUsers() {
-		Map<String, Object> parameters = new HashMap<>();
-		parameters.put(SAML2AssertionValidationParameters.SC_VALID_RECIPIENTS, Collections.singleton("blah"));
-		ValidationContext context = mock(ValidationContext.class);
-		given(context.getStaticParameters()).willReturn(parameters);
-		OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-		provider.setAssertionValidator(
-				OpenSamlAuthenticationProvider.createDefaultAssertionValidator((assertionToken) -> context));
-		Response response = response();
-		Assertion assertion = assertion();
-		response.getAssertions().add(assertion);
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				ASSERTING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		// @formatter:off
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> provider.authenticate(token)).isInstanceOf(Saml2AuthenticationException.class)
-				.satisfies((error) -> assertThat(error).hasMessageContaining("Invalid assertion"));
-		// @formatter:on
-		verify(context, atLeastOnce()).getStaticParameters();
-	}
-
-	@Test
-	public void authenticateWithSHA1SignatureThenItSucceeds() throws Exception {
-		Response response = response();
-		Assertion assertion = TestOpenSamlObjects.signed(assertion(),
-				TestSaml2X509Credentials.assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID,
-				SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
-		response.getAssertions().add(assertion);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		this.provider.authenticate(token);
-	}
-
-	@Test
-	public void setAssertionValidatorWhenNullThenIllegalArgument() {
-		// @formatter:off
-		assertThatIllegalArgumentException()
-				.isThrownBy(() -> this.provider.setAssertionValidator(null));
-		// @formatter:on
-	}
-
-	@Test
-	public void createDefaultResponseAuthenticationConverterWhenResponseThenConverts() {
-		Response response = TestOpenSamlObjects.signedResponseWithOneAssertion();
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		ResponseToken responseToken = new ResponseToken(response, token);
-		Saml2Authentication authentication = OpenSamlAuthenticationProvider
-				.createDefaultResponseAuthenticationConverter().convert(responseToken);
-		assertThat(authentication.getName()).isEqualTo("test@saml.user");
-	}
-
-	@Test
-	public void authenticateWhenResponseAuthenticationConverterConfiguredThenUses() {
-		Converter<ResponseToken, Saml2Authentication> authenticationConverter = mock(Converter.class);
-		OpenSamlAuthenticationProvider provider = new OpenSamlAuthenticationProvider();
-		provider.setResponseAuthenticationConverter(authenticationConverter);
-		Response response = TestOpenSamlObjects.signedResponseWithOneAssertion();
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		provider.authenticate(token);
-		verify(authenticationConverter).convert(any());
-	}
-
-	@Test
-	public void setResponseAuthenticationConverterWhenNullThenIllegalArgument() {
-		// @formatter:off
-		assertThatIllegalArgumentException()
-				.isThrownBy(() -> this.provider.setResponseAuthenticationConverter(null));
-		// @formatter:on
-	}
-
-	@Test
-	public void setResponseElementsDecrypterWhenNullThenIllegalArgument() {
-		assertThatIllegalArgumentException().isThrownBy(() -> this.provider.setResponseElementsDecrypter(null));
-	}
-
-	@Test
-	public void setAssertionElementsDecrypterWhenNullThenIllegalArgument() {
-		assertThatIllegalArgumentException().isThrownBy(() -> this.provider.setAssertionElementsDecrypter(null));
-	}
-
-	@Test
-	public void authenticateWhenCustomResponseElementsDecrypterThenDecryptsResponse() {
-		Response response = response();
-		Assertion assertion = assertion();
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		response.getEncryptedAssertions().add(new EncryptedAssertionBuilder().buildObject());
-		TestOpenSamlObjects.signed(response, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		this.provider.setResponseElementsDecrypter((tuple) -> tuple.getResponse().getAssertions().add(assertion));
-		Authentication authentication = this.provider.authenticate(token);
-		assertThat(authentication.getName()).isEqualTo("test@saml.user");
-	}
-
-	@Test
-	public void authenticateWhenCustomAssertionElementsDecrypterThenDecryptsAssertion() {
-		Response response = response();
-		Assertion assertion = assertion();
-		EncryptedID id = new EncryptedIDBuilder().buildObject();
-		id.setEncryptedData(new EncryptedDataBuilder().buildObject());
-		assertion.getSubject().setEncryptedID(id);
-		TestOpenSamlObjects.signed(assertion, TestSaml2X509Credentials.assertingPartySigningCredential(),
-				RELYING_PARTY_ENTITY_ID);
-		response.getAssertions().add(assertion);
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		this.provider.setAssertionElementsDecrypter((tuple) -> {
-			NameID name = new NameIDBuilder().buildObject();
-			name.setValue("decrypted name");
-			tuple.getAssertion().getSubject().setNameID(name);
-		});
-		Authentication authentication = this.provider.authenticate(token);
-		assertThat(authentication.getName()).isEqualTo("decrypted name");
-	}
-
-	@Test
-	public void authenticateWhenResponseStatusIsNotSuccessThenFails() {
-		Response response = TestOpenSamlObjects.signedResponseWithOneAssertion(
-				(r) -> r.setStatus(TestOpenSamlObjects.status(StatusCode.AUTHN_FAILED)));
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		assertThatExceptionOfType(Saml2AuthenticationException.class)
-				.isThrownBy(() -> this.provider.authenticate(token))
-				.satisfies(errorOf(Saml2ErrorCodes.INVALID_RESPONSE, "Invalid status"));
-	}
-
-	@Test
-	public void authenticateWhenResponseStatusIsSuccessThenSucceeds() {
-		Response response = TestOpenSamlObjects
-				.signedResponseWithOneAssertion((r) -> r.setStatus(TestOpenSamlObjects.successStatus()));
-		Saml2AuthenticationToken token = token(response, verifying(registration()));
-		Authentication authentication = this.provider.authenticate(token);
-		assertThat(authentication.getName()).isEqualTo("test@saml.user");
-	}
-
-	private <T extends XMLObject> T build(QName qName) {
-		return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName);
-	}
-
-	private String serialize(XMLObject object) {
-		try {
-			Marshaller marshaller = XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(object);
-			Element element = marshaller.marshall(object);
-			return SerializeSupport.nodeToString(element);
-		}
-		catch (MarshallingException ex) {
-			throw new Saml2Exception(ex);
-		}
-	}
-
-	private Consumer<Saml2AuthenticationException> errorOf(String errorCode) {
-		return errorOf(errorCode, null);
-	}
-
-	private Consumer<Saml2AuthenticationException> errorOf(String errorCode, String description) {
-		return (ex) -> {
-			assertThat(ex.getSaml2Error().getErrorCode()).isEqualTo(errorCode);
-			if (StringUtils.hasText(description)) {
-				assertThat(ex.getSaml2Error().getDescription()).contains(description);
-			}
-		};
-	}
-
-	private Response response() {
-		Response response = TestOpenSamlObjects.response();
-		response.setIssueInstant(DateTime.now());
-		return response;
-	}
-
-	private Response response(String destination, String issuerEntityId) {
-		Response response = TestOpenSamlObjects.response(destination, issuerEntityId);
-		response.setIssueInstant(DateTime.now());
-		return response;
-	}
-
-	private Assertion assertion() {
-		Assertion assertion = TestOpenSamlObjects.assertion();
-		assertion.setIssueInstant(DateTime.now());
-		for (SubjectConfirmation confirmation : assertion.getSubject().getSubjectConfirmations()) {
-			SubjectConfirmationData data = confirmation.getSubjectConfirmationData();
-			data.setNotBefore(DateTime.now().minus(Duration.millis(5 * 60 * 1000)));
-			data.setNotOnOrAfter(DateTime.now().plus(Duration.millis(5 * 60 * 1000)));
-		}
-		Conditions conditions = assertion.getConditions();
-		conditions.setNotBefore(DateTime.now().minus(Duration.millis(5 * 60 * 1000)));
-		conditions.setNotOnOrAfter(DateTime.now().plus(Duration.millis(5 * 60 * 1000)));
-		return assertion;
-	}
-
-	private List<AttributeStatement> attributeStatements() {
-		List<AttributeStatement> attributeStatements = TestOpenSamlObjects.attributeStatements();
-		AttributeBuilder attributeBuilder = new AttributeBuilder();
-		Attribute registeredDateAttr = attributeBuilder.buildObject();
-		registeredDateAttr.setName("registeredDate");
-		XSDateTime registeredDate = new XSDateTimeBuilder().buildObject(AttributeValue.DEFAULT_ELEMENT_NAME,
-				XSDateTime.TYPE_NAME);
-		registeredDate.setValue(DateTime.parse("1970-01-01T00:00:00Z"));
-		registeredDateAttr.getAttributeValues().add(registeredDate);
-		attributeStatements.get(0).getAttributes().add(registeredDateAttr);
-		return attributeStatements;
-	}
-
-	private Saml2AuthenticationToken token() {
-		Response response = response();
-		RelyingPartyRegistration registration = verifying(registration()).build();
-		return new Saml2AuthenticationToken(registration, serialize(response));
-	}
-
-	private Saml2AuthenticationToken token(Response response, RelyingPartyRegistration.Builder registration) {
-		return new Saml2AuthenticationToken(registration.build(), serialize(response));
-	}
-
-	private RelyingPartyRegistration.Builder registration() {
-		return TestRelyingPartyRegistrations.noCredentials().entityId(RELYING_PARTY_ENTITY_ID)
-				.assertionConsumerServiceLocation(DESTINATION)
-				.assertingPartyDetails((party) -> party.entityId(ASSERTING_PARTY_ENTITY_ID));
-	}
-
-	private RelyingPartyRegistration.Builder verifying(RelyingPartyRegistration.Builder builder) {
-		return builder.assertingPartyDetails((party) -> party
-				.verificationX509Credentials((c) -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential())));
-	}
-
-	private RelyingPartyRegistration.Builder decrypting(RelyingPartyRegistration.Builder builder) {
-		return builder
-				.decryptionX509Credentials((c) -> c.add(TestSaml2X509Credentials.relyingPartyDecryptingCredential()));
-	}
-
-}

+ 0 - 66
saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolverTests.java

@@ -1,66 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.saml2.provider.service.web.authentication.logout;
-
-import jakarta.servlet.http.HttpServletRequest;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.security.authentication.TestingAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
-import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
-import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-
-/**
- * Tests for {@link OpenSaml3LogoutRequestResolver}
- */
-public class OpenSaml3LogoutRequestResolverTests {
-
-	RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = mock(RelyingPartyRegistrationResolver.class);
-
-	@Test
-	public void resolveWhenCustomParametersConsumerThenUses() {
-		OpenSaml3LogoutRequestResolver logoutRequestResolver = new OpenSaml3LogoutRequestResolver(
-				this.relyingPartyRegistrationResolver);
-		logoutRequestResolver.setParametersConsumer((parameters) -> parameters.getLogoutRequest().setID("myid"));
-		HttpServletRequest request = new MockHttpServletRequest();
-		RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration()
-				.assertingPartyDetails((party) -> party.singleLogoutServiceLocation("https://ap.example.com/logout"))
-				.build();
-		Authentication authentication = new TestingAuthenticationToken("user", "password");
-		given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
-		Saml2LogoutRequest logoutRequest = logoutRequestResolver.resolve(request, authentication);
-		assertThat(logoutRequest.getId()).isEqualTo("myid");
-	}
-
-	@Test
-	public void setParametersConsumerWhenNullThenIllegalArgument() {
-		OpenSaml3LogoutRequestResolver logoutRequestResolver = new OpenSaml3LogoutRequestResolver(
-				this.relyingPartyRegistrationResolver);
-		assertThatExceptionOfType(IllegalArgumentException.class)
-				.isThrownBy(() -> logoutRequestResolver.setParametersConsumer(null));
-	}
-
-}

+ 0 - 78
saml2/saml2-service-provider/src/opensaml3Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolverTests.java

@@ -1,78 +0,0 @@
-/*
- * Copyright 2002-2021 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.security.saml2.provider.service.web.authentication.logout;
-
-import java.util.function.Consumer;
-
-import org.junit.jupiter.api.Test;
-import org.opensaml.saml.saml2.core.LogoutRequest;
-
-import org.springframework.mock.web.MockHttpServletRequest;
-import org.springframework.security.authentication.TestingAuthenticationToken;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.saml2.core.Saml2ParameterNames;
-import org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects;
-import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse;
-import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
-import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
-import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
-import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml3LogoutResponseResolver.LogoutResponseParameters;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-/**
- * Tests for {@link OpenSaml3LogoutResponseResolver}
- */
-public class OpenSaml3LogoutResponseResolverTests {
-
-	RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = mock(RelyingPartyRegistrationResolver.class);
-
-	@Test
-	public void resolveWhenCustomParametersConsumerThenUses() {
-		OpenSaml3LogoutResponseResolver logoutResponseResolver = new OpenSaml3LogoutResponseResolver(
-				this.relyingPartyRegistrationResolver);
-		Consumer<LogoutResponseParameters> parametersConsumer = mock(Consumer.class);
-		logoutResponseResolver.setParametersConsumer(parametersConsumer);
-		MockHttpServletRequest request = new MockHttpServletRequest();
-		RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration()
-				.assertingPartyDetails(
-						(party) -> party.singleLogoutServiceResponseLocation("https://ap.example.com/logout"))
-				.build();
-		Authentication authentication = new TestingAuthenticationToken("user", "password");
-		LogoutRequest logoutRequest = TestOpenSamlObjects.assertingPartyLogoutRequest(registration);
-		request.setParameter(Saml2ParameterNames.SAML_REQUEST,
-				Saml2Utils.samlEncode(OpenSamlSigningUtils.serialize(logoutRequest).getBytes()));
-		given(this.relyingPartyRegistrationResolver.resolve(any(), any())).willReturn(registration);
-		Saml2LogoutResponse logoutResponse = logoutResponseResolver.resolve(request, authentication);
-		assertThat(logoutResponse).isNotNull();
-		verify(parametersConsumer).accept(any());
-	}
-
-	@Test
-	public void setParametersConsumerWhenNullThenIllegalArgument() {
-		OpenSaml3LogoutRequestResolver logoutRequestResolver = new OpenSaml3LogoutRequestResolver(
-				this.relyingPartyRegistrationResolver);
-		assertThatExceptionOfType(IllegalArgumentException.class)
-				.isThrownBy(() -> logoutRequestResolver.setParametersConsumer(null));
-	}
-
-}

+ 1 - 2
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/DefaultSaml2AuthenticatedPrincipalTests.java

@@ -22,7 +22,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.joda.time.DateTime;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -72,7 +71,7 @@ public class DefaultSaml2AuthenticatedPrincipalTests {
 	@Test
 	public void getAttributeWhenDistinctValuesThenReturnsValues() {
 		final Boolean registered = true;
-		final Instant registeredDate = Instant.ofEpochMilli(DateTime.parse("1970-01-01T00:00:00Z").getMillis());
+		final Instant registeredDate = Instant.parse("1970-01-01T00:00:00Z");
 		Map<String, List<Object>> attributes = new LinkedHashMap<>();
 		attributes.put("registration", Arrays.asList(registered, registeredDate));
 		DefaultSaml2AuthenticatedPrincipal principal = new DefaultSaml2AuthenticatedPrincipal("user", attributes);

+ 0 - 0
saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java → saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProviderTests.java


+ 0 - 0
saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolverTests.java → saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/OpenSaml4AuthenticationRequestResolverTests.java


+ 0 - 0
saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolverTests.java → saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolverTests.java


+ 0 - 0
saml2/saml2-service-provider/src/opensaml4Test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java → saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolverTests.java


部分文件因文件數量過多而無法顯示