Reformat code using spring-javaformat
Run `./gradlew format` to reformat all java files. Issue gh-8945
This commit is contained in:
+44
-31
@@ -36,17 +36,21 @@ import static java.lang.Boolean.TRUE;
|
||||
import static org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport.setParserPool;
|
||||
|
||||
/**
|
||||
* An initialization service for initializing OpenSAML. Each Spring Security OpenSAML-based component invokes
|
||||
* the {@link #initialize()} method at static initialization time.
|
||||
* An initialization service for initializing OpenSAML. Each Spring Security
|
||||
* OpenSAML-based component invokes the {@link #initialize()} method at static
|
||||
* initialization time.
|
||||
*
|
||||
* {@link #initialize()} is idempotent and may be safely called in custom classes that need OpenSAML to be
|
||||
* initialized in order to function correctly. It's recommended that you call this {@link #initialize()} method
|
||||
* when using Spring Security and OpenSAML instead of OpenSAML's {@link InitializationService#initialize()}.
|
||||
* {@link #initialize()} is idempotent and may be safely called in custom classes that
|
||||
* need OpenSAML to be initialized in order to function correctly. It's recommended that
|
||||
* you call this {@link #initialize()} method when using Spring Security and OpenSAML
|
||||
* instead of OpenSAML's {@link InitializationService#initialize()}.
|
||||
*
|
||||
* The primary purpose of {@link #initialize()} is to prepare OpenSAML's {@link XMLObjectProviderRegistry}
|
||||
* with some reasonable defaults. Any changes that Spring Security makes to the registry happen in this method.
|
||||
* The primary purpose of {@link #initialize()} is to prepare OpenSAML's
|
||||
* {@link XMLObjectProviderRegistry} with some reasonable defaults. Any changes that
|
||||
* Spring Security makes to the registry happen in this method.
|
||||
*
|
||||
* To override those defaults, call {@link #requireInitialize(Consumer)} and change the registry:
|
||||
* To override those defaults, call {@link #requireInitialize(Consumer)} and change the
|
||||
* registry:
|
||||
*
|
||||
* <pre>
|
||||
* static {
|
||||
@@ -59,45 +63,50 @@ import static org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport.setP
|
||||
*
|
||||
* {@link #requireInitialize(Consumer)} may only be called once per application.
|
||||
*
|
||||
* If the application already initialized OpenSAML before {@link #requireInitialize(Consumer)} was called,
|
||||
* then the configuration changes will not be applied and an exception will be thrown. The reason for this is to
|
||||
* alert you to the fact that there are likely some initialization ordering problems in your application that
|
||||
* would otherwise lead to an unpredictable state.
|
||||
* If the application already initialized OpenSAML before
|
||||
* {@link #requireInitialize(Consumer)} was called, then the configuration changes will
|
||||
* not be applied and an exception will be thrown. The reason for this is to alert you to
|
||||
* the fact that there are likely some initialization ordering problems in your
|
||||
* application that would otherwise lead to an unpredictable state.
|
||||
*
|
||||
* If you must change the registry's configuration in multiple places in your application, you are expected
|
||||
* to handle the initialization ordering issues yourself instead of trying to call {@link #requireInitialize(Consumer)}
|
||||
* multiple times.
|
||||
* If you must change the registry's configuration in multiple places in your application,
|
||||
* you are expected to handle the initialization ordering issues yourself instead of
|
||||
* trying to call {@link #requireInitialize(Consumer)} multiple times.
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 5.4
|
||||
*/
|
||||
public class OpenSamlInitializationService {
|
||||
|
||||
private static final Log log = LogFactory.getLog(OpenSamlInitializationService.class);
|
||||
|
||||
private static final AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Ready OpenSAML for use and configure it with reasonable defaults.
|
||||
*
|
||||
* Initialization is guaranteed to happen only once per application. This method will passively return
|
||||
* {@code false} if initialization already took place earlier in the application.
|
||||
*
|
||||
* @return whether or not initialization was performed. The first thread to initialize OpenSAML will
|
||||
* return {@code true} while the rest will return {@code false}.
|
||||
* Initialization is guaranteed to happen only once per application. This method will
|
||||
* passively return {@code false} if initialization already took place earlier in the
|
||||
* application.
|
||||
* @return whether or not initialization was performed. The first thread to initialize
|
||||
* OpenSAML will return {@code true} while the rest will return {@code false}.
|
||||
* @throws Saml2Exception if OpenSAML failed to initialize
|
||||
*/
|
||||
public static boolean initialize() {
|
||||
return initialize(registry -> {});
|
||||
return initialize(registry -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ready OpenSAML for use, configure it with reasonable defaults, and modify the {@link XMLObjectProviderRegistry}
|
||||
* using the provided {@link Consumer}.
|
||||
* Ready OpenSAML for use, configure it with reasonable defaults, and modify the
|
||||
* {@link XMLObjectProviderRegistry} using the provided {@link Consumer}.
|
||||
*
|
||||
* Initialization is guaranteed to happen only once per application. This method will throw an exception
|
||||
* if initialization already took place earlier in the application.
|
||||
*
|
||||
* @param registryConsumer the {@link Consumer} to further configure the {@link XMLObjectProviderRegistry}
|
||||
* @throws Saml2Exception if initialization already happened previously or if OpenSAML failed to initialize
|
||||
* Initialization is guaranteed to happen only once per application. This method will
|
||||
* throw an exception if initialization already took place earlier in the application.
|
||||
* @param registryConsumer the {@link Consumer} to further configure the
|
||||
* {@link XMLObjectProviderRegistry}
|
||||
* @throws Saml2Exception if initialization already happened previously or if OpenSAML
|
||||
* failed to initialize
|
||||
*/
|
||||
public static void requireInitialize(Consumer<XMLObjectProviderRegistry> registryConsumer) {
|
||||
if (!initialize(registryConsumer)) {
|
||||
@@ -111,7 +120,8 @@ public class OpenSamlInitializationService {
|
||||
|
||||
try {
|
||||
InitializationService.initialize();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
|
||||
@@ -129,7 +139,8 @@ public class OpenSamlInitializationService {
|
||||
|
||||
try {
|
||||
parserPool.initialize();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
setParserPool(parserPool);
|
||||
@@ -138,9 +149,11 @@ public class OpenSamlInitializationService {
|
||||
|
||||
log.debug("Initialized OpenSAML");
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
log.debug("Refused to re-initialize OpenSAML");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-8
@@ -25,21 +25,23 @@ import org.springframework.util.Assert;
|
||||
* A representation of an SAML 2.0 Error.
|
||||
*
|
||||
* <p>
|
||||
* At a minimum, an error response will contain an error code.
|
||||
* The commonly used error code are defined in this class
|
||||
* or a new codes can be defined in the future as arbitrary strings.
|
||||
* At a minimum, an error response will contain an error code. The commonly used error
|
||||
* code are defined in this class or a new codes can be defined in the future as arbitrary
|
||||
* strings.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.2
|
||||
*/
|
||||
public class Saml2Error implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
private final String errorCode;
|
||||
|
||||
private final String description;
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2Error} using the provided parameters.
|
||||
*
|
||||
* @param errorCode the error code
|
||||
* @param description the error description
|
||||
*/
|
||||
@@ -51,7 +53,6 @@ public class Saml2Error implements Serializable {
|
||||
|
||||
/**
|
||||
* Returns the error code.
|
||||
*
|
||||
* @return the error code
|
||||
*/
|
||||
public final String getErrorCode() {
|
||||
@@ -60,7 +61,6 @@ public class Saml2Error implements Serializable {
|
||||
|
||||
/**
|
||||
* Returns the error description.
|
||||
*
|
||||
* @return the error description
|
||||
*/
|
||||
public final String getDescription() {
|
||||
@@ -69,7 +69,7 @@ public class Saml2Error implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.getErrorCode() + "] " +
|
||||
(this.getDescription() != null ? this.getDescription() : "");
|
||||
return "[" + this.getErrorCode() + "] " + (this.getDescription() != null ? this.getDescription() : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+38
-34
@@ -22,80 +22,84 @@ package org.springframework.security.saml2.core;
|
||||
* @since 5.2
|
||||
*/
|
||||
public interface Saml2ErrorCodes {
|
||||
|
||||
/**
|
||||
* SAML Data does not represent a SAML 2 Response object.
|
||||
* A valid XML object was received, but that object was not a
|
||||
* SAML 2 Response object of type {@code ResponseType} per specification
|
||||
* SAML Data does not represent a SAML 2 Response object. A valid XML object was
|
||||
* received, but that object was not a SAML 2 Response object of type
|
||||
* {@code ResponseType} per specification
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=46
|
||||
*/
|
||||
String UNKNOWN_RESPONSE_CLASS = "unknown_response_class";
|
||||
|
||||
/**
|
||||
* The response data is malformed or incomplete.
|
||||
* An invalid XML object was received, and XML unmarshalling failed.
|
||||
* The response data is malformed or incomplete. An invalid XML object was received,
|
||||
* and XML unmarshalling failed.
|
||||
*/
|
||||
String MALFORMED_RESPONSE_DATA = "malformed_response_data";
|
||||
|
||||
/**
|
||||
* Response destination does not match the request URL.
|
||||
* A SAML 2 response object was received at a URL that
|
||||
* did not match the URL stored in the {code Destination} attribute
|
||||
* in the Response object.
|
||||
* Response destination does not match the request URL. A SAML 2 response object was
|
||||
* received at a URL that did not match the URL stored in the {code Destination}
|
||||
* attribute in the Response object.
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=38
|
||||
*/
|
||||
String INVALID_DESTINATION = "invalid_destination";
|
||||
|
||||
/**
|
||||
* The assertion was not valid.
|
||||
* The assertion used for authentication failed validation.
|
||||
* Details around the failure will be present in the error description.
|
||||
* The assertion was not valid. The assertion used for authentication failed
|
||||
* validation. Details around the failure will be present in the error description.
|
||||
*/
|
||||
String INVALID_ASSERTION = "invalid_assertion";
|
||||
|
||||
/**
|
||||
* The signature of response or assertion was invalid.
|
||||
* Either the response or the assertion was missing a signature
|
||||
* or the signature could not be verified using the system's
|
||||
* configured credentials. Most commonly the IDP's
|
||||
* X509 certificate.
|
||||
* The signature of response or assertion was invalid. Either the response or the
|
||||
* assertion was missing a signature or the signature could not be verified using the
|
||||
* system's configured credentials. Most commonly the IDP's X509 certificate.
|
||||
*/
|
||||
String INVALID_SIGNATURE = "invalid_signature";
|
||||
|
||||
/**
|
||||
* The assertion did not contain a subject element.
|
||||
* The subject element, type SubjectType, contains
|
||||
* a {@code NameID} or an {@code EncryptedID} that is used
|
||||
* to assign the authenticated principal an identifier,
|
||||
* typically a username.
|
||||
* The assertion did not contain a subject element. The subject element, type
|
||||
* SubjectType, contains a {@code NameID} or an {@code EncryptedID} that is used to
|
||||
* assign the authenticated principal an identifier, typically a username.
|
||||
*
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=18
|
||||
*/
|
||||
String SUBJECT_NOT_FOUND = "subject_not_found";
|
||||
|
||||
/**
|
||||
* The subject did not contain a user identifier
|
||||
* The assertion contained a subject element, but the subject
|
||||
* element did not have a {@code NameID} or {@code EncryptedID}
|
||||
* element
|
||||
* The subject did not contain a user identifier The assertion contained a subject
|
||||
* element, but the subject element did not have a {@code NameID} or
|
||||
* {@code EncryptedID} element
|
||||
*
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=18
|
||||
*/
|
||||
String USERNAME_NOT_FOUND = "username_not_found";
|
||||
|
||||
/**
|
||||
* The system failed to decrypt an assertion or a name identifier.
|
||||
* This error code will be thrown if the decryption of either a
|
||||
* {@code EncryptedAssertion} or {@code EncryptedID} fails.
|
||||
* The system failed to decrypt an assertion or a name identifier. This error code
|
||||
* will be thrown if the decryption of either a {@code EncryptedAssertion} or
|
||||
* {@code EncryptedID} fails.
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=17
|
||||
*/
|
||||
String DECRYPTION_ERROR = "decryption_error";
|
||||
|
||||
/**
|
||||
* An Issuer element contained a value that didn't
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=15
|
||||
*/
|
||||
String INVALID_ISSUER = "invalid_issuer";
|
||||
|
||||
/**
|
||||
* An error happened during validation.
|
||||
* Used when internal, non classified, errors are caught during the
|
||||
* authentication process.
|
||||
* An error happened during validation. Used when internal, non classified, errors are
|
||||
* caught during the authentication process.
|
||||
*/
|
||||
String INTERNAL_VALIDATION_ERROR = "internal_validation_error";
|
||||
|
||||
/**
|
||||
* The relying party registration was not found.
|
||||
* The registration ID did not correspond to any relying party registration.
|
||||
* The relying party registration was not found. The registration ID did not
|
||||
* correspond to any relying party registration.
|
||||
*/
|
||||
String RELYING_PARTY_REGISTRATION_NOT_FOUND = "relying_party_registration_not_found";
|
||||
|
||||
}
|
||||
|
||||
+31
-36
@@ -29,34 +29,35 @@ import static org.springframework.util.Assert.notNull;
|
||||
import static org.springframework.util.Assert.state;
|
||||
|
||||
/**
|
||||
* An object for holding a public certificate, any associated private key, and its intended
|
||||
* <a href="https://www.oasis-open.org/committees/download.php/8958/sstc-saml-implementation-guidelines-draft-01.pdf">
|
||||
* usages
|
||||
* </a>
|
||||
* (Line 584, Section 4.3 Credentials).
|
||||
* An object for holding a public certificate, any associated private key, and its
|
||||
* intended <a href=
|
||||
* "https://www.oasis-open.org/committees/download.php/8958/sstc-saml-implementation-guidelines-draft-01.pdf">
|
||||
* usages </a> (Line 584, Section 4.3 Credentials).
|
||||
*
|
||||
* @since 5.4
|
||||
* @author Filip Hanik
|
||||
* @author Josh Cummings
|
||||
*/
|
||||
public final class Saml2X509Credential {
|
||||
|
||||
public enum Saml2X509CredentialType {
|
||||
VERIFICATION,
|
||||
ENCRYPTION,
|
||||
SIGNING,
|
||||
DECRYPTION,
|
||||
|
||||
VERIFICATION, ENCRYPTION, SIGNING, DECRYPTION,
|
||||
|
||||
}
|
||||
|
||||
private final PrivateKey privateKey;
|
||||
|
||||
private final X509Certificate certificate;
|
||||
|
||||
private final Set<Saml2X509CredentialType> credentialTypes;
|
||||
|
||||
/**
|
||||
* Creates a {@link Saml2X509Credential} using the provided parameters
|
||||
*
|
||||
* @param certificate the credential's public certificiate
|
||||
* @param types the credential's intended usages, must be one of {@link Saml2X509CredentialType#VERIFICATION} or
|
||||
* {@link Saml2X509CredentialType#ENCRYPTION} or both.
|
||||
* @param types the credential's intended usages, must be one of
|
||||
* {@link Saml2X509CredentialType#VERIFICATION} or
|
||||
* {@link Saml2X509CredentialType#ENCRYPTION} or both.
|
||||
*/
|
||||
public Saml2X509Credential(X509Certificate certificate, Saml2X509CredentialType... types) {
|
||||
this(null, false, certificate, types);
|
||||
@@ -65,11 +66,11 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* Creates a {@link Saml2X509Credential} using the provided parameters
|
||||
*
|
||||
* @param privateKey the credential's private key
|
||||
* @param certificate the credential's public certificate
|
||||
* @param types the credential's intended usages, must be one of {@link Saml2X509CredentialType#SIGNING} or
|
||||
* {@link Saml2X509CredentialType#DECRYPTION} or both.
|
||||
* @param types the credential's intended usages, must be one of
|
||||
* {@link Saml2X509CredentialType#SIGNING} or
|
||||
* {@link Saml2X509CredentialType#DECRYPTION} or both.
|
||||
*/
|
||||
public Saml2X509Credential(PrivateKey privateKey, X509Certificate certificate, Saml2X509CredentialType... types) {
|
||||
this(privateKey, true, certificate, types);
|
||||
@@ -78,7 +79,6 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* Creates a {@link Saml2X509Credential} using the provided parameters
|
||||
*
|
||||
* @param privateKey the credential's private key
|
||||
* @param certificate the credential's public certificate
|
||||
* @param types the credential's intended usages
|
||||
@@ -125,10 +125,7 @@ public final class Saml2X509Credential {
|
||||
return new Saml2X509Credential(privateKey, certificate, Saml2X509Credential.Saml2X509CredentialType.SIGNING);
|
||||
}
|
||||
|
||||
private Saml2X509Credential(
|
||||
PrivateKey privateKey,
|
||||
boolean keyRequired,
|
||||
X509Certificate certificate,
|
||||
private Saml2X509Credential(PrivateKey privateKey, boolean keyRequired, X509Certificate certificate,
|
||||
Saml2X509CredentialType... types) {
|
||||
notNull(certificate, "certificate cannot be null");
|
||||
notEmpty(types, "credentials types cannot be empty");
|
||||
@@ -142,7 +139,6 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* Get the private key for this credential
|
||||
*
|
||||
* @return the private key, may be null
|
||||
* @see {@link #Saml2X509Credential(PrivateKey, X509Certificate, Saml2X509CredentialType...)}
|
||||
*/
|
||||
@@ -152,7 +148,6 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* Get the public certificate for this credential
|
||||
*
|
||||
* @return the public certificate
|
||||
*/
|
||||
public X509Certificate getCertificate() {
|
||||
@@ -161,7 +156,6 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* Indicate whether this credential can be used for signing
|
||||
*
|
||||
* @return true if the credential has a {@link Saml2X509CredentialType#SIGNING} type
|
||||
*/
|
||||
public boolean isSigningCredential() {
|
||||
@@ -170,8 +164,8 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* Indicate whether this credential can be used for decryption
|
||||
*
|
||||
* @return true if the credential has a {@link Saml2X509CredentialType#DECRYPTION} type
|
||||
* @return true if the credential has a {@link Saml2X509CredentialType#DECRYPTION}
|
||||
* type
|
||||
*/
|
||||
public boolean isDecryptionCredential() {
|
||||
return getCredentialTypes().contains(Saml2X509CredentialType.DECRYPTION);
|
||||
@@ -179,8 +173,8 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* Indicate whether this credential can be used for verification
|
||||
*
|
||||
* @return true if the credential has a {@link Saml2X509CredentialType#VERIFICATION} type
|
||||
* @return true if the credential has a {@link Saml2X509CredentialType#VERIFICATION}
|
||||
* type
|
||||
*/
|
||||
public boolean isVerificationCredential() {
|
||||
return getCredentialTypes().contains(Saml2X509CredentialType.VERIFICATION);
|
||||
@@ -188,8 +182,8 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* Indicate whether this credential can be used for encryption
|
||||
*
|
||||
* @return true if the credential has a {@link Saml2X509CredentialType#ENCRYPTION} type
|
||||
* @return true if the credential has a {@link Saml2X509CredentialType#ENCRYPTION}
|
||||
* type
|
||||
*/
|
||||
public boolean isEncryptionCredential() {
|
||||
return getCredentialTypes().contains(Saml2X509CredentialType.ENCRYPTION);
|
||||
@@ -197,7 +191,6 @@ public final class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* List all this credential's intended usages
|
||||
*
|
||||
* @return the set of this credential's intended usages
|
||||
*/
|
||||
public Set<Saml2X509CredentialType> getCredentialTypes() {
|
||||
@@ -206,12 +199,13 @@ public final class Saml2X509Credential {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
Saml2X509Credential that = (Saml2X509Credential) o;
|
||||
return Objects.equals(this.privateKey, that.privateKey) &&
|
||||
this.certificate.equals(that.certificate) &&
|
||||
this.credentialTypes.equals(that.credentialTypes);
|
||||
return Objects.equals(this.privateKey, that.privateKey) && this.certificate.equals(that.certificate)
|
||||
&& this.credentialTypes.equals(that.credentialTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -228,7 +222,8 @@ public final class Saml2X509Credential {
|
||||
break;
|
||||
}
|
||||
}
|
||||
state(valid, () -> usage +" is not a valid usage for this credential");
|
||||
state(valid, () -> usage + " is not a valid usage for this credential");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+42
-33
@@ -32,34 +32,41 @@ import static org.springframework.util.Assert.state;
|
||||
* Saml2X509Credential is meant to hold an X509 certificate, or an X509 certificate and a
|
||||
* private key. Per:
|
||||
* https://www.oasis-open.org/committees/download.php/8958/sstc-saml-implementation-guidelines-draft-01.pdf
|
||||
* Line: 584, Section 4.3 Credentials Used for both signing, signature verification and encryption/decryption
|
||||
* Line: 584, Section 4.3 Credentials Used for both signing, signature verification and
|
||||
* encryption/decryption
|
||||
*
|
||||
* @since 5.2
|
||||
* @deprecated Use {@link org.springframework.security.saml2.core.Saml2X509Credential} instead
|
||||
* @deprecated Use {@link org.springframework.security.saml2.core.Saml2X509Credential}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class Saml2X509Credential {
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType} instead
|
||||
* @deprecated Use
|
||||
* {@link org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public enum Saml2X509CredentialType {
|
||||
VERIFICATION,
|
||||
ENCRYPTION,
|
||||
SIGNING,
|
||||
DECRYPTION,
|
||||
|
||||
VERIFICATION, ENCRYPTION, SIGNING, DECRYPTION,
|
||||
|
||||
}
|
||||
|
||||
private final PrivateKey privateKey;
|
||||
|
||||
private final X509Certificate certificate;
|
||||
|
||||
private final Set<Saml2X509CredentialType> credentialTypes;
|
||||
|
||||
/**
|
||||
* Creates a Saml2X509Credentials representing Identity Provider credentials for
|
||||
* verification, encryption or both.
|
||||
* @param certificate an IDP X509Certificate, cannot be null
|
||||
* @param types credential types, must be one of {@link Saml2X509CredentialType#VERIFICATION} or
|
||||
* {@link Saml2X509CredentialType#ENCRYPTION} or both.
|
||||
* @param types credential types, must be one of
|
||||
* {@link Saml2X509CredentialType#VERIFICATION} or
|
||||
* {@link Saml2X509CredentialType#ENCRYPTION} or both.
|
||||
*/
|
||||
public Saml2X509Credential(X509Certificate certificate, Saml2X509CredentialType... types) {
|
||||
this(null, false, certificate, types);
|
||||
@@ -70,9 +77,11 @@ public class Saml2X509Credential {
|
||||
* Creates a Saml2X509Credentials representing Service Provider credentials for
|
||||
* signing, decryption or both.
|
||||
* @param privateKey a private key used for signing or decryption, cannot be null
|
||||
* @param certificate an SP X509Certificate shared with identity providers, cannot be null
|
||||
* @param types credential types, must be one of {@link Saml2X509CredentialType#SIGNING} or
|
||||
* {@link Saml2X509CredentialType#DECRYPTION} or both.
|
||||
* @param certificate an SP X509Certificate shared with identity providers, cannot be
|
||||
* null
|
||||
* @param types credential types, must be one of
|
||||
* {@link Saml2X509CredentialType#SIGNING} or
|
||||
* {@link Saml2X509CredentialType#DECRYPTION} or both.
|
||||
*/
|
||||
public Saml2X509Credential(PrivateKey privateKey, X509Certificate certificate, Saml2X509CredentialType... types) {
|
||||
this(privateKey, true, certificate, types);
|
||||
@@ -87,10 +96,7 @@ public class Saml2X509Credential {
|
||||
this.credentialTypes = types;
|
||||
}
|
||||
|
||||
private Saml2X509Credential(
|
||||
PrivateKey privateKey,
|
||||
boolean keyRequired,
|
||||
X509Certificate certificate,
|
||||
private Saml2X509Credential(PrivateKey privateKey, boolean keyRequired, X509Certificate certificate,
|
||||
Saml2X509CredentialType... types) {
|
||||
notNull(certificate, "certificate cannot be null");
|
||||
notEmpty(types, "credentials types cannot be empty");
|
||||
@@ -102,10 +108,9 @@ public class Saml2X509Credential {
|
||||
this.credentialTypes = new LinkedHashSet<>(asList(types));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the credential has a private key and can be used for signing, the types will contain
|
||||
* {@link Saml2X509CredentialType#SIGNING}.
|
||||
* Returns true if the credential has a private key and can be used for signing, the
|
||||
* types will contain {@link Saml2X509CredentialType#SIGNING}.
|
||||
* @return true if the credential is a {@link Saml2X509CredentialType#SIGNING} type
|
||||
*/
|
||||
public boolean isSigningCredential() {
|
||||
@@ -113,8 +118,8 @@ public class Saml2X509Credential {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the credential has a private key and can be used for decryption, the types will contain
|
||||
* {@link Saml2X509CredentialType#DECRYPTION}.
|
||||
* Returns true if the credential has a private key and can be used for decryption,
|
||||
* the types will contain {@link Saml2X509CredentialType#DECRYPTION}.
|
||||
* @return true if the credential is a {@link Saml2X509CredentialType#DECRYPTION} type
|
||||
*/
|
||||
public boolean isDecryptionCredential() {
|
||||
@@ -122,18 +127,20 @@ public class Saml2X509Credential {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the credential has a certificate and can be used for signature verification, the types will contain
|
||||
* {@link Saml2X509CredentialType#VERIFICATION}.
|
||||
* @return true if the credential is a {@link Saml2X509CredentialType#VERIFICATION} type
|
||||
* Returns true if the credential has a certificate and can be used for signature
|
||||
* verification, the types will contain {@link Saml2X509CredentialType#VERIFICATION}.
|
||||
* @return true if the credential is a {@link Saml2X509CredentialType#VERIFICATION}
|
||||
* type
|
||||
*/
|
||||
public boolean isSignatureVerficationCredential() {
|
||||
return getCredentialTypes().contains(Saml2X509CredentialType.VERIFICATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the credential has a certificate and can be used for signature verification, the types will contain
|
||||
* {@link Saml2X509CredentialType#VERIFICATION}.
|
||||
* @return true if the credential is a {@link Saml2X509CredentialType#VERIFICATION} type
|
||||
* Returns true if the credential has a certificate and can be used for signature
|
||||
* verification, the types will contain {@link Saml2X509CredentialType#VERIFICATION}.
|
||||
* @return true if the credential is a {@link Saml2X509CredentialType#VERIFICATION}
|
||||
* type
|
||||
*/
|
||||
public boolean isEncryptionCredential() {
|
||||
return getCredentialTypes().contains(Saml2X509CredentialType.ENCRYPTION);
|
||||
@@ -166,12 +173,13 @@ public class Saml2X509Credential {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
Saml2X509Credential that = (Saml2X509Credential) o;
|
||||
return Objects.equals(this.privateKey, that.privateKey) &&
|
||||
this.certificate.equals(that.certificate) &&
|
||||
this.credentialTypes.equals(that.credentialTypes);
|
||||
return Objects.equals(this.privateKey, that.privateKey) && this.certificate.equals(that.certificate)
|
||||
&& this.credentialTypes.equals(that.credentialTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,7 +196,8 @@ public class Saml2X509Credential {
|
||||
break;
|
||||
}
|
||||
}
|
||||
state(valid, () -> usage +" is not a valid usage for this credential");
|
||||
state(valid, () -> usage + " is not a valid usage for this credential");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
-23
@@ -23,11 +23,12 @@ import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Data holder for {@code AuthNRequest} parameters to be sent using either the
|
||||
* {@link Saml2MessageBinding#POST} or {@link Saml2MessageBinding#REDIRECT} binding.
|
||||
* Data will be encoded and possibly deflated, but will not be escaped for transport,
|
||||
* ie URL encoded, {@link org.springframework.web.util.UriUtils#encode(String, Charset)}
|
||||
* or HTML encoded, {@link org.springframework.web.util.HtmlUtils#htmlEscape(String)}.
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf (line 2031)
|
||||
* {@link Saml2MessageBinding#POST} or {@link Saml2MessageBinding#REDIRECT} binding. Data
|
||||
* will be encoded and possibly deflated, but will not be escaped for transport, ie URL
|
||||
* encoded, {@link org.springframework.web.util.UriUtils#encode(String, Charset)} or HTML
|
||||
* encoded, {@link org.springframework.web.util.HtmlUtils#htmlEscape(String)}.
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf
|
||||
* (line 2031)
|
||||
*
|
||||
* @see Saml2AuthenticationRequestFactory#createPostAuthenticationRequest(Saml2AuthenticationRequestContext)
|
||||
* @see Saml2AuthenticationRequestFactory#createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext)
|
||||
@@ -36,19 +37,20 @@ import java.nio.charset.Charset;
|
||||
abstract class AbstractSaml2AuthenticationRequest {
|
||||
|
||||
private final String samlRequest;
|
||||
|
||||
private final String relayState;
|
||||
|
||||
private final String authenticationRequestUri;
|
||||
|
||||
/**
|
||||
* Mandatory constructor for the {@link AbstractSaml2AuthenticationRequest}
|
||||
* @param samlRequest - the SAMLRequest XML data, SAML encoded, cannot be empty or null
|
||||
* @param samlRequest - the SAMLRequest XML data, SAML encoded, cannot be empty or
|
||||
* null
|
||||
* @param relayState - RelayState value that accompanies the request, may be null
|
||||
* @param authenticationRequestUri - The authenticationRequestUri, a URL, where to send the XML message, cannot be empty or null
|
||||
* @param authenticationRequestUri - The authenticationRequestUri, a URL, where to
|
||||
* send the XML message, cannot be empty or null
|
||||
*/
|
||||
AbstractSaml2AuthenticationRequest(
|
||||
String samlRequest,
|
||||
String relayState,
|
||||
String authenticationRequestUri) {
|
||||
AbstractSaml2AuthenticationRequest(String samlRequest, String relayState, String authenticationRequestUri) {
|
||||
Assert.hasText(samlRequest, "samlRequest cannot be null or empty");
|
||||
Assert.hasText(authenticationRequestUri, "authenticationRequestUri cannot be null or empty");
|
||||
this.authenticationRequestUri = authenticationRequestUri;
|
||||
@@ -57,9 +59,10 @@ abstract class AbstractSaml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AuthNRequest XML value to be sent. This value is already encoded for transport.
|
||||
* If {@link #getBinding()} is {@link Saml2MessageBinding#REDIRECT} the value is deflated and SAML encoded.
|
||||
* If {@link #getBinding()} is {@link Saml2MessageBinding#POST} the value is SAML encoded.
|
||||
* Returns the AuthNRequest XML value to be sent. This value is already encoded for
|
||||
* transport. If {@link #getBinding()} is {@link Saml2MessageBinding#REDIRECT} the
|
||||
* value is deflated and SAML encoded. If {@link #getBinding()} is
|
||||
* {@link Saml2MessageBinding#POST} the value is SAML encoded.
|
||||
* @return the SAMLRequest parameter value
|
||||
*/
|
||||
public String getSamlRequest() {
|
||||
@@ -83,8 +86,9 @@ abstract class AbstractSaml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binding this AuthNRequest will be sent and
|
||||
* encoded with. If {@link Saml2MessageBinding#REDIRECT} is used, the DEFLATE encoding will be automatically applied.
|
||||
* Returns the binding this AuthNRequest will be sent and encoded with. If
|
||||
* {@link Saml2MessageBinding#REDIRECT} is used, the DEFLATE encoding will be
|
||||
* automatically applied.
|
||||
* @return the binding this message will be sent with.
|
||||
*/
|
||||
public abstract Saml2MessageBinding getBinding();
|
||||
@@ -93,8 +97,11 @@ abstract class AbstractSaml2AuthenticationRequest {
|
||||
* A builder for {@link AbstractSaml2AuthenticationRequest} and its subclasses.
|
||||
*/
|
||||
static class Builder<T extends Builder<T>> {
|
||||
|
||||
String authenticationRequestUri;
|
||||
|
||||
String samlRequest;
|
||||
|
||||
String relayState;
|
||||
|
||||
protected Builder() {
|
||||
@@ -109,12 +116,10 @@ abstract class AbstractSaml2AuthenticationRequest {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the {@code RelayState} parameter that will accompany this AuthNRequest
|
||||
*
|
||||
* @param relayState the relay state value, unencoded. if null or empty, the parameter will be removed from the
|
||||
* map.
|
||||
* @param relayState the relay state value, unencoded. if null or empty, the
|
||||
* parameter will be removed from the map.
|
||||
* @return this object
|
||||
*/
|
||||
public T relayState(String relayState) {
|
||||
@@ -124,7 +129,6 @@ abstract class AbstractSaml2AuthenticationRequest {
|
||||
|
||||
/**
|
||||
* Sets the {@code SAMLRequest} parameter that will accompany this AuthNRequest
|
||||
*
|
||||
* @param samlRequest the SAMLRequest parameter.
|
||||
* @return this object
|
||||
*/
|
||||
@@ -134,8 +138,8 @@ abstract class AbstractSaml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code authenticationRequestUri}, a URL that will receive the AuthNRequest message
|
||||
*
|
||||
* Sets the {@code authenticationRequestUri}, a URL that will receive the
|
||||
* AuthNRequest message
|
||||
* @param authenticationRequestUri the relay state value, unencoded.
|
||||
* @return this object
|
||||
*/
|
||||
@@ -143,6 +147,7 @@ abstract class AbstractSaml2AuthenticationRequest {
|
||||
this.authenticationRequestUri = authenticationRequestUri;
|
||||
return _this();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -31,6 +31,7 @@ import java.util.Map;
|
||||
public class DefaultSaml2AuthenticatedPrincipal implements Saml2AuthenticatedPrincipal, Serializable {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Map<String, List<Object>> attributes;
|
||||
|
||||
public DefaultSaml2AuthenticatedPrincipal(String name, Map<String, List<Object>> attributes) {
|
||||
@@ -50,4 +51,5 @@ public class DefaultSaml2AuthenticatedPrincipal implements Saml2AuthenticatedPri
|
||||
public Map<String, List<Object>> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+132
-103
@@ -129,39 +129,48 @@ import static org.springframework.security.saml2.core.Saml2ErrorCodes.SUBJECT_NO
|
||||
import static org.springframework.util.Assert.notNull;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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).
|
||||
* 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>
|
||||
* <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.
|
||||
* 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>
|
||||
* <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.
|
||||
* 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>
|
||||
* <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.
|
||||
* 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>
|
||||
* <p>
|
||||
* This provider does not perform an X509 certificate validation on the configured asserting party, IDP, verification
|
||||
* certificates.
|
||||
* This provider does not perform an X509 certificate validation on the configured
|
||||
* asserting party, IDP, verification certificates.
|
||||
* </p>
|
||||
*
|
||||
* @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://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>
|
||||
*/
|
||||
public final class OpenSamlAuthenticationProvider implements AuthenticationProvider {
|
||||
@@ -173,32 +182,35 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
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 -> singletonList(new SimpleGrantedAuthority("ROLE_USER")));
|
||||
private Converter<Assertion, Collection<? extends GrantedAuthority>> authoritiesExtractor = (a -> singletonList(
|
||||
new SimpleGrantedAuthority("ROLE_USER")));
|
||||
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = (a -> a);
|
||||
|
||||
private Duration responseTimeValidationSkew = Duration.ofMinutes(5);
|
||||
|
||||
private Function<Saml2AuthenticationToken, Converter<Response, AbstractAuthenticationToken>> authenticationConverter =
|
||||
token -> response -> {
|
||||
Assertion assertion = CollectionUtils.firstElement(response.getAssertions());
|
||||
String username = assertion.getSubject().getNameID().getValue();
|
||||
Map<String, List<Object>> attributes = getAssertionAttributes(assertion);
|
||||
return new Saml2Authentication(
|
||||
new DefaultSaml2AuthenticatedPrincipal(username, attributes), token.getSaml2Response(),
|
||||
this.authoritiesMapper.mapAuthorities(getAssertionAuthorities(assertion)));
|
||||
};
|
||||
private Function<Saml2AuthenticationToken, Converter<Response, AbstractAuthenticationToken>> authenticationConverter = token -> response -> {
|
||||
Assertion assertion = CollectionUtils.firstElement(response.getAssertions());
|
||||
String username = assertion.getSubject().getNameID().getValue();
|
||||
Map<String, List<Object>> attributes = getAssertionAttributes(assertion);
|
||||
return new Saml2Authentication(new DefaultSaml2AuthenticatedPrincipal(username, attributes),
|
||||
token.getSaml2Response(), this.authoritiesMapper.mapAuthorities(getAssertionAuthorities(assertion)));
|
||||
};
|
||||
|
||||
private Converter<Saml2AuthenticationToken, SignatureTrustEngine> signatureTrustEngineConverter = new SignatureTrustEngineConverter();
|
||||
|
||||
private Converter<Tuple, SAML20AssertionValidator> assertionValidatorConverter = new SAML20AssertionValidatorConverter();
|
||||
|
||||
private Collection<ConditionValidator> conditionValidators = Collections
|
||||
.singleton(new AudienceRestrictionConditionValidator());
|
||||
|
||||
private Converter<Tuple, ValidationContext> validationContextConverter = new ValidationContextConverter();
|
||||
|
||||
private Converter<Saml2AuthenticationToken, SignatureTrustEngine> signatureTrustEngineConverter =
|
||||
new SignatureTrustEngineConverter();
|
||||
private Converter<Tuple, SAML20AssertionValidator> assertionValidatorConverter =
|
||||
new SAML20AssertionValidatorConverter();
|
||||
private Collection<ConditionValidator> conditionValidators =
|
||||
Collections.singleton(new AudienceRestrictionConditionValidator());
|
||||
private Converter<Tuple, ValidationContext> validationContextConverter =
|
||||
new ValidationContextConverter();
|
||||
private Converter<Saml2AuthenticationToken, Decrypter> decrypterConverter = new DecrypterConverter();
|
||||
|
||||
/**
|
||||
@@ -212,48 +224,47 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the the collection of {@link ConditionValidator}s used when validating an assertion.
|
||||
*
|
||||
* Set the the collection of {@link ConditionValidator}s used when validating an
|
||||
* assertion.
|
||||
* @param conditionValidators the collection of validators to use
|
||||
* @since 5.4
|
||||
*/
|
||||
public void setConditionValidators(
|
||||
Collection<ConditionValidator> conditionValidators) {
|
||||
public void setConditionValidators(Collection<ConditionValidator> conditionValidators) {
|
||||
|
||||
Assert.notEmpty(conditionValidators, "conditionValidators cannot be empty");
|
||||
this.conditionValidators = conditionValidators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the strategy for retrieving the {@link ValidationContext} used when
|
||||
* validating an assertion.
|
||||
*
|
||||
* Set the strategy for retrieving the {@link ValidationContext} used when validating
|
||||
* an assertion.
|
||||
* @param validationContextConverter the strategy to use
|
||||
* @since 5.4
|
||||
*/
|
||||
public void setValidationContextConverter(
|
||||
Converter<Tuple, ValidationContext> validationContextConverter) {
|
||||
public void setValidationContextConverter(Converter<Tuple, ValidationContext> validationContextConverter) {
|
||||
|
||||
Assert.notNull(validationContextConverter, "validationContextConverter cannot be empty");
|
||||
this.validationContextConverter = validationContextConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
public void setAuthoritiesExtractor(Converter<Assertion, Collection<? extends GrantedAuthority>> authoritiesExtractor) {
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
notNull(authoritiesMapper, "authoritiesMapper cannot be null");
|
||||
@@ -271,8 +282,7 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
|
||||
/**
|
||||
* @param authentication the authentication request object, must be of type
|
||||
* {@link Saml2AuthenticationToken}
|
||||
*
|
||||
* {@link Saml2AuthenticationToken}
|
||||
* @return {@link Saml2Authentication} if the assertion is valid
|
||||
* @throws AuthenticationException if a validation exception occurs
|
||||
*/
|
||||
@@ -284,9 +294,11 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
Response response = parse(serializedResponse);
|
||||
process(token, response);
|
||||
return this.authenticationConverter.apply(token).convert(response);
|
||||
} catch (Saml2AuthenticationException e) {
|
||||
}
|
||||
catch (Saml2AuthenticationException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw authException(INTERNAL_VALIDATION_ERROR, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@@ -305,8 +317,8 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
|
||||
private Response parse(String response) throws Saml2Exception, Saml2AuthenticationException {
|
||||
try {
|
||||
Document document = this.parserPool.parse(new ByteArrayInputStream(
|
||||
response.getBytes(StandardCharsets.UTF_8)));
|
||||
Document document = this.parserPool
|
||||
.parse(new ByteArrayInputStream(response.getBytes(StandardCharsets.UTF_8)));
|
||||
Element element = document.getDocumentElement();
|
||||
return (Response) this.responseUnmarshaller.unmarshall(element);
|
||||
}
|
||||
@@ -327,8 +339,8 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
Decrypter decrypter = this.decrypterConverter.convert(token);
|
||||
List<Assertion> assertions = decryptAssertions(decrypter, response);
|
||||
if (!isSigned(responseSigned, assertions)) {
|
||||
throw authException(INVALID_SIGNATURE, "Either the response or one of the assertions is unsigned. " +
|
||||
"Please either sign the response or all of the assertions.");
|
||||
throw authException(INVALID_SIGNATURE, "Either the response or one of the assertions is unsigned. "
|
||||
+ "Please either sign the response or all of the assertions.");
|
||||
}
|
||||
validationExceptions.putAll(validateAssertions(token, response));
|
||||
|
||||
@@ -343,12 +355,15 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Successfully processed SAML Response [" + response.getID() + "]");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.debug("Found " + validationExceptions.size() + " validation errors in SAML response [" + response.getID() + "]: " +
|
||||
validationExceptions.values());
|
||||
} else if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found " + validationExceptions.size() + " validation errors in SAML response [" + response.getID() + "]");
|
||||
logger.debug("Found " + validationExceptions.size() + " validation errors in SAML response ["
|
||||
+ response.getID() + "]: " + validationExceptions.values());
|
||||
}
|
||||
else if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found " + validationExceptions.size() + " validation errors in SAML response ["
|
||||
+ response.getID() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,8 +372,8 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Saml2AuthenticationException> validateResponse
|
||||
(Saml2AuthenticationToken token, Response response) {
|
||||
private Map<String, Saml2AuthenticationException> validateResponse(Saml2AuthenticationToken token,
|
||||
Response response) {
|
||||
|
||||
Map<String, Saml2AuthenticationException> validationExceptions = new HashMap<>();
|
||||
String issuer = response.getIssuer().getValue();
|
||||
@@ -367,7 +382,8 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
|
||||
try {
|
||||
profileValidator.validate(response.getSignature());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
validationExceptions.put(INVALID_SIGNATURE, authException(INVALID_SIGNATURE,
|
||||
"Invalid signature for SAML Response [" + response.getID() + "]: ", e));
|
||||
}
|
||||
@@ -375,13 +391,15 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
try {
|
||||
CriteriaSet criteriaSet = new CriteriaSet();
|
||||
criteriaSet.add(new EvaluableEntityIDCredentialCriterion(new EntityIdCriterion(issuer)));
|
||||
criteriaSet.add(new EvaluableProtocolRoleDescriptorCriterion(new ProtocolCriterion(SAMLConstants.SAML20P_NS)));
|
||||
criteriaSet.add(
|
||||
new EvaluableProtocolRoleDescriptorCriterion(new ProtocolCriterion(SAMLConstants.SAML20P_NS)));
|
||||
criteriaSet.add(new EvaluableUsageCredentialCriterion(new UsageCriterion(UsageType.SIGNING)));
|
||||
if (!this.signatureTrustEngineConverter.convert(token).validate(response.getSignature(), criteriaSet)) {
|
||||
validationExceptions.put(INVALID_SIGNATURE, authException(INVALID_SIGNATURE,
|
||||
"Invalid signature for SAML Response [" + response.getID() + "]"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
validationExceptions.put(INVALID_SIGNATURE, authException(INVALID_SIGNATURE,
|
||||
"Invalid signature for SAML Response [" + response.getID() + "]: ", e));
|
||||
}
|
||||
@@ -403,14 +421,14 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
return validationExceptions;
|
||||
}
|
||||
|
||||
private List<Assertion> decryptAssertions
|
||||
(Decrypter decrypter, Response response) {
|
||||
private List<Assertion> decryptAssertions(Decrypter decrypter, Response response) {
|
||||
List<Assertion> assertions = new ArrayList<>();
|
||||
for (EncryptedAssertion encryptedAssertion : response.getEncryptedAssertions()) {
|
||||
try {
|
||||
Assertion assertion = decrypter.decrypt(encryptedAssertion);
|
||||
assertions.add(assertion);
|
||||
} catch (DecryptionException e) {
|
||||
}
|
||||
catch (DecryptionException e) {
|
||||
throw authException(DECRYPTION_ERROR, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@@ -418,8 +436,8 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
return response.getAssertions();
|
||||
}
|
||||
|
||||
private Map<String, Saml2AuthenticationException> validateAssertions
|
||||
(Saml2AuthenticationToken token, Response response) {
|
||||
private Map<String, Saml2AuthenticationException> validateAssertions(Saml2AuthenticationToken token,
|
||||
Response response) {
|
||||
List<Assertion> assertions = response.getAssertions();
|
||||
if (assertions.isEmpty()) {
|
||||
throw authException(MALFORMED_RESPONSE_DATA, "No assertions found in response.");
|
||||
@@ -444,10 +462,10 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
context.getValidationFailureMessage());
|
||||
validationExceptions.put(INVALID_ASSERTION, authException(INVALID_ASSERTION, message));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s",
|
||||
assertion.getID(), ((Response) assertion.getParent()).getID(),
|
||||
e.getMessage());
|
||||
}
|
||||
catch (Exception e) {
|
||||
String message = String.format("Invalid assertion [%s] for SAML response [%s]: %s", assertion.getID(),
|
||||
((Response) assertion.getParent()).getID(), e.getMessage());
|
||||
validationExceptions.put(INVALID_ASSERTION, authException(INVALID_ASSERTION, message, e));
|
||||
}
|
||||
}
|
||||
@@ -480,7 +498,8 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
NameID nameId = (NameID) decrypter.decrypt(assertion.getSubject().getEncryptedID());
|
||||
assertion.getSubject().setNameID(nameId);
|
||||
return nameId;
|
||||
} catch (DecryptionException e) {
|
||||
}
|
||||
catch (DecryptionException e) {
|
||||
throw authException(DECRYPTION_ERROR, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
@@ -534,19 +553,22 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
try {
|
||||
Element element = marshaller.marshall(xsAny);
|
||||
return SerializeSupport.nodeToString(element);
|
||||
} catch (MarshallingException e) {
|
||||
}
|
||||
catch (MarshallingException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
return xsAny.getTextContent();
|
||||
}
|
||||
|
||||
private static class SignatureTrustEngineConverter implements Converter<Saml2AuthenticationToken, SignatureTrustEngine> {
|
||||
private static class SignatureTrustEngineConverter
|
||||
implements Converter<Saml2AuthenticationToken, SignatureTrustEngine> {
|
||||
|
||||
@Override
|
||||
public SignatureTrustEngine convert(Saml2AuthenticationToken token) {
|
||||
Set<Credential> credentials = new HashSet<>();
|
||||
Collection<Saml2X509Credential> keys = token.getRelyingPartyRegistration().getAssertingPartyDetails().getVerificationX509Credentials();
|
||||
Collection<Saml2X509Credential> keys = token.getRelyingPartyRegistration().getAssertingPartyDetails()
|
||||
.getVerificationX509Credentials();
|
||||
for (Saml2X509Credential key : keys) {
|
||||
BasicX509Credential cred = new BasicX509Credential(key.getCertificate());
|
||||
cred.setUsageType(UsageType.SIGNING);
|
||||
@@ -554,11 +576,10 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
credentials.add(cred);
|
||||
}
|
||||
CredentialResolver credentialsResolver = new CollectionCredentialResolver(credentials);
|
||||
return new ExplicitKeySignatureTrustEngine(
|
||||
credentialsResolver,
|
||||
DefaultSecurityConfigurationBootstrap.buildBasicInlineKeyInfoCredentialResolver()
|
||||
);
|
||||
return new ExplicitKeySignatureTrustEngine(credentialsResolver,
|
||||
DefaultSecurityConfigurationBootstrap.buildBasicInlineKeyInfoCredentialResolver());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ValidationContextConverter implements Converter<Tuple, ValidationContext> {
|
||||
@@ -571,14 +592,19 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
params.put(CLOCK_SKEW, OpenSamlAuthenticationProvider.this.responseTimeValidationSkew.toMillis());
|
||||
params.put(COND_VALID_AUDIENCES, singleton(audience));
|
||||
params.put(SC_VALID_RECIPIENTS, singleton(recipient));
|
||||
params.put(SIGNATURE_REQUIRED, false); // this verification is performed earlier
|
||||
params.put(SIGNATURE_REQUIRED, false); // this verification is performed
|
||||
// earlier
|
||||
return new ValidationContext(params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class SAML20AssertionValidatorConverter implements Converter<Tuple, SAML20AssertionValidator> {
|
||||
|
||||
private final Collection<SubjectConfirmationValidator> subjects = new ArrayList<>();
|
||||
|
||||
private final Collection<StatementValidator> statements = new ArrayList<>();
|
||||
|
||||
private final SignaturePrevalidator validator = new SAMLSignatureProfileValidator();
|
||||
|
||||
SAML20AssertionValidatorConverter() {
|
||||
@@ -595,22 +621,19 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
|
||||
@Override
|
||||
public SAML20AssertionValidator convert(Tuple tuple) {
|
||||
Collection<ConditionValidator> conditions =
|
||||
OpenSamlAuthenticationProvider.this.conditionValidators;
|
||||
Collection<ConditionValidator> conditions = OpenSamlAuthenticationProvider.this.conditionValidators;
|
||||
return new SAML20AssertionValidator(conditions, this.subjects, this.statements,
|
||||
OpenSamlAuthenticationProvider.this.signatureTrustEngineConverter.convert(tuple.authentication),
|
||||
this.validator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class DecrypterConverter implements Converter<Saml2AuthenticationToken, Decrypter> {
|
||||
|
||||
private final EncryptedKeyResolver encryptedKeyResolver = new ChainingEncryptedKeyResolver(
|
||||
asList(
|
||||
new InlineEncryptedKeyResolver(),
|
||||
new EncryptedElementTypeEncryptedKeyResolver(),
|
||||
new SimpleRetrievalMethodEncryptedKeyResolver()
|
||||
)
|
||||
);
|
||||
asList(new InlineEncryptedKeyResolver(), new EncryptedElementTypeEncryptedKeyResolver(),
|
||||
new SimpleRetrievalMethodEncryptedKeyResolver()));
|
||||
|
||||
@Override
|
||||
public Decrypter convert(Saml2AuthenticationToken token) {
|
||||
@@ -624,6 +647,7 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
decrypter.setRootInNewDocument(true);
|
||||
return decrypter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Saml2Error validationError(String code, String description) {
|
||||
@@ -643,12 +667,15 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
}
|
||||
|
||||
/**
|
||||
* A tuple containing the authentication token and the associated OpenSAML {@link Response}.
|
||||
* A tuple containing the authentication token and the associated OpenSAML
|
||||
* {@link Response}.
|
||||
*
|
||||
* @since 5.4
|
||||
*/
|
||||
public static class Tuple {
|
||||
|
||||
private final Saml2AuthenticationToken authentication;
|
||||
|
||||
private final Response response;
|
||||
|
||||
private Tuple(Saml2AuthenticationToken authentication, Response response) {
|
||||
@@ -663,5 +690,7 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi
|
||||
public Response getResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+53
-76
@@ -70,6 +70,7 @@ import static org.springframework.util.StringUtils.hasText;
|
||||
* @since 5.2
|
||||
*/
|
||||
public class OpenSamlAuthenticationRequestFactory implements Saml2AuthenticationRequestFactory {
|
||||
|
||||
static {
|
||||
OpenSamlInitializationService.initialize();
|
||||
}
|
||||
@@ -77,19 +78,20 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
private Clock clock = Clock.systemUTC();
|
||||
|
||||
private AuthnRequestMarshaller marshaller;
|
||||
|
||||
private AuthnRequestBuilder authnRequestBuilder;
|
||||
|
||||
private IssuerBuilder issuerBuilder;
|
||||
|
||||
private Converter<Saml2AuthenticationRequestContext, String> protocolBindingResolver =
|
||||
context -> {
|
||||
if (context == null) {
|
||||
return SAMLConstants.SAML2_POST_BINDING_URI;
|
||||
}
|
||||
return context.getRelyingPartyRegistration().getAssertionConsumerServiceBinding().getUrn();
|
||||
};
|
||||
private Converter<Saml2AuthenticationRequestContext, String> protocolBindingResolver = context -> {
|
||||
if (context == null) {
|
||||
return SAMLConstants.SAML2_POST_BINDING_URI;
|
||||
}
|
||||
return context.getRelyingPartyRegistration().getAssertionConsumerServiceBinding().getUrn();
|
||||
};
|
||||
|
||||
private Function<Saml2AuthenticationRequestContext, Consumer<AuthnRequest>> authnRequestConsumerResolver
|
||||
= context -> authnRequest -> {};
|
||||
private Function<Saml2AuthenticationRequestContext, Consumer<AuthnRequest>> authnRequestConsumerResolver = context -> authnRequest -> {
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an {@link OpenSamlAuthenticationRequestFactory}
|
||||
@@ -100,19 +102,18 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
.getMarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME);
|
||||
this.authnRequestBuilder = (AuthnRequestBuilder) registry.getBuilderFactory()
|
||||
.getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME);
|
||||
this.issuerBuilder = (IssuerBuilder) registry.getBuilderFactory()
|
||||
.getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
|
||||
this.issuerBuilder = (IssuerBuilder) registry.getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String createAuthenticationRequest(Saml2AuthenticationRequest request) {
|
||||
AuthnRequest authnRequest = createAuthnRequest(request.getIssuer(),
|
||||
request.getDestination(), request.getAssertionConsumerServiceUrl(),
|
||||
this.protocolBindingResolver.convert(null));
|
||||
AuthnRequest authnRequest = createAuthnRequest(request.getIssuer(), request.getDestination(),
|
||||
request.getAssertionConsumerServiceUrl(), this.protocolBindingResolver.convert(null));
|
||||
for (org.springframework.security.saml2.credentials.Saml2X509Credential credential : request.getCredentials()) {
|
||||
if (credential.isSigningCredential()) {
|
||||
Credential cred = getSigningCredential(credential.getCertificate(), credential.getPrivateKey(), request.getIssuer());
|
||||
Credential cred = getSigningCredential(credential.getCertificate(), credential.getPrivateKey(),
|
||||
request.getIssuer());
|
||||
return serialize(sign(authnRequest, cred));
|
||||
}
|
||||
}
|
||||
@@ -125,41 +126,34 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
@Override
|
||||
public Saml2PostAuthenticationRequest createPostAuthenticationRequest(Saml2AuthenticationRequestContext context) {
|
||||
AuthnRequest authnRequest = createAuthnRequest(context);
|
||||
String xml = context.getRelyingPartyRegistration().getAssertingPartyDetails().getWantAuthnRequestsSigned() ?
|
||||
serialize(sign(authnRequest, context.getRelyingPartyRegistration())) :
|
||||
serialize(authnRequest);
|
||||
String xml = context.getRelyingPartyRegistration().getAssertingPartyDetails().getWantAuthnRequestsSigned()
|
||||
? serialize(sign(authnRequest, context.getRelyingPartyRegistration())) : serialize(authnRequest);
|
||||
|
||||
return Saml2PostAuthenticationRequest.withAuthenticationRequestContext(context)
|
||||
.samlRequest(samlEncode(xml.getBytes(UTF_8)))
|
||||
.build();
|
||||
.samlRequest(samlEncode(xml.getBytes(UTF_8))).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Saml2RedirectAuthenticationRequest createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext context) {
|
||||
public Saml2RedirectAuthenticationRequest createRedirectAuthenticationRequest(
|
||||
Saml2AuthenticationRequestContext context) {
|
||||
AuthnRequest authnRequest = createAuthnRequest(context);
|
||||
String xml = serialize(authnRequest);
|
||||
Builder result = Saml2RedirectAuthenticationRequest.withAuthenticationRequestContext(context);
|
||||
String deflatedAndEncoded = samlEncode(samlDeflate(xml));
|
||||
result.samlRequest(deflatedAndEncoded)
|
||||
.relayState(context.getRelayState());
|
||||
result.samlRequest(deflatedAndEncoded).relayState(context.getRelayState());
|
||||
|
||||
if (context.getRelyingPartyRegistration().getAssertingPartyDetails().getWantAuthnRequestsSigned()) {
|
||||
Collection<Saml2X509Credential> signingCredentials = context.getRelyingPartyRegistration().getSigningX509Credentials();
|
||||
Collection<Saml2X509Credential> signingCredentials = context.getRelyingPartyRegistration()
|
||||
.getSigningX509Credentials();
|
||||
for (Saml2X509Credential credential : signingCredentials) {
|
||||
Credential cred = getSigningCredential(credential.getCertificate(), credential.getPrivateKey(), "");
|
||||
Map<String, String> signedParams = signQueryParameters(
|
||||
cred,
|
||||
deflatedAndEncoded,
|
||||
Map<String, String> signedParams = signQueryParameters(cred, deflatedAndEncoded,
|
||||
context.getRelayState());
|
||||
return result
|
||||
.samlRequest(signedParams.get("SAMLRequest"))
|
||||
.relayState(signedParams.get("RelayState"))
|
||||
.sigAlg(signedParams.get("SigAlg"))
|
||||
.signature(signedParams.get("Signature"))
|
||||
.build();
|
||||
return result.samlRequest(signedParams.get("SAMLRequest")).relayState(signedParams.get("RelayState"))
|
||||
.sigAlg(signedParams.get("SigAlg")).signature(signedParams.get("Signature")).build();
|
||||
}
|
||||
throw new Saml2Exception("No signing credential provided");
|
||||
}
|
||||
@@ -168,15 +162,14 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
}
|
||||
|
||||
private AuthnRequest createAuthnRequest(Saml2AuthenticationRequestContext context) {
|
||||
AuthnRequest authnRequest = createAuthnRequest(context.getIssuer(),
|
||||
context.getDestination(), context.getAssertionConsumerServiceUrl(),
|
||||
this.protocolBindingResolver.convert(context));
|
||||
AuthnRequest authnRequest = createAuthnRequest(context.getIssuer(), context.getDestination(),
|
||||
context.getAssertionConsumerServiceUrl(), this.protocolBindingResolver.convert(context));
|
||||
this.authnRequestConsumerResolver.apply(context).accept(authnRequest);
|
||||
return authnRequest;
|
||||
}
|
||||
|
||||
private AuthnRequest createAuthnRequest
|
||||
(String issuer, String destination, String assertionConsumerServiceUrl, String protocolBinding) {
|
||||
private AuthnRequest createAuthnRequest(String issuer, String destination, String assertionConsumerServiceUrl,
|
||||
String protocolBinding) {
|
||||
AuthnRequest auth = this.authnRequestBuilder.buildObject();
|
||||
auth.setID("ARQ" + UUID.randomUUID().toString().substring(1));
|
||||
auth.setIssueInstant(new DateTime(this.clock.millis()));
|
||||
@@ -193,7 +186,6 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
|
||||
/**
|
||||
* Set the {@link AuthnRequest} post-processor resolver
|
||||
*
|
||||
* @param authnRequestConsumerResolver
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -204,10 +196,7 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
}
|
||||
|
||||
/**
|
||||
* '
|
||||
* Use this {@link Clock} with {@link Instant#now()} for generating
|
||||
* timestamps
|
||||
*
|
||||
* ' Use this {@link Clock} with {@link Instant#now()} for generating timestamps
|
||||
* @param clock
|
||||
*/
|
||||
public void setClock(Clock clock) {
|
||||
@@ -218,20 +207,20 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
/**
|
||||
* Sets the {@code protocolBinding} to use when generating authentication requests.
|
||||
* Acceptable values are {@link SAMLConstants#SAML2_POST_BINDING_URI} and
|
||||
* {@link SAMLConstants#SAML2_REDIRECT_BINDING_URI}
|
||||
* The IDP will be reading this value in the {@code AuthNRequest} to determine how to
|
||||
* send the Response/Assertion to the ACS URL, assertion consumer service URL.
|
||||
*
|
||||
* {@link SAMLConstants#SAML2_REDIRECT_BINDING_URI} The IDP will be reading this value
|
||||
* in the {@code AuthNRequest} to determine how to send the Response/Assertion to the
|
||||
* ACS URL, assertion consumer service URL.
|
||||
* @param protocolBinding either {@link SAMLConstants#SAML2_POST_BINDING_URI} or
|
||||
* {@link SAMLConstants#SAML2_REDIRECT_BINDING_URI}
|
||||
* @throws IllegalArgumentException if the protocolBinding is not valid
|
||||
* @deprecated Use {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.Builder#assertionConsumerServiceBinding(Saml2MessageBinding)}
|
||||
* @deprecated Use
|
||||
* {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.Builder#assertionConsumerServiceBinding(Saml2MessageBinding)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProtocolBinding(String protocolBinding) {
|
||||
boolean isAllowedBinding = SAMLConstants.SAML2_POST_BINDING_URI.equals(protocolBinding) ||
|
||||
SAMLConstants.SAML2_REDIRECT_BINDING_URI.equals(protocolBinding);
|
||||
boolean isAllowedBinding = SAMLConstants.SAML2_POST_BINDING_URI.equals(protocolBinding)
|
||||
|| SAMLConstants.SAML2_REDIRECT_BINDING_URI.equals(protocolBinding);
|
||||
if (!isAllowedBinding) {
|
||||
throw new IllegalArgumentException("Invalid protocol binding: " + protocolBinding);
|
||||
}
|
||||
@@ -240,8 +229,8 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
|
||||
private AuthnRequest sign(AuthnRequest authnRequest, RelyingPartyRegistration relyingPartyRegistration) {
|
||||
for (Saml2X509Credential credential : relyingPartyRegistration.getSigningX509Credentials()) {
|
||||
Credential cred = getSigningCredential(
|
||||
credential.getCertificate(), credential.getPrivateKey(), relyingPartyRegistration.getEntityId());
|
||||
Credential cred = getSigningCredential(credential.getCertificate(), credential.getPrivateKey(),
|
||||
relyingPartyRegistration.getEntityId());
|
||||
return sign(authnRequest, cred);
|
||||
}
|
||||
throw new IllegalArgumentException("No signing credential provided");
|
||||
@@ -256,7 +245,8 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
try {
|
||||
SignatureSupport.signObject(authnRequest, parameters);
|
||||
return authnRequest;
|
||||
} catch (MarshallingException | SignatureException | SecurityException e) {
|
||||
}
|
||||
catch (MarshallingException | SignatureException | SecurityException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
@@ -268,36 +258,21 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
return cred;
|
||||
}
|
||||
|
||||
private Map<String, String> signQueryParameters(
|
||||
Credential credential,
|
||||
String samlRequest,
|
||||
String relayState) {
|
||||
private Map<String, String> signQueryParameters(Credential credential, String samlRequest, String relayState) {
|
||||
Assert.notNull(samlRequest, "samlRequest cannot be null");
|
||||
String algorithmUri = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256;
|
||||
StringBuilder queryString = new StringBuilder();
|
||||
queryString
|
||||
.append("SAMLRequest")
|
||||
.append("=")
|
||||
.append(UriUtils.encode(samlRequest, StandardCharsets.ISO_8859_1))
|
||||
queryString.append("SAMLRequest").append("=").append(UriUtils.encode(samlRequest, StandardCharsets.ISO_8859_1))
|
||||
.append("&");
|
||||
if (hasText(relayState)) {
|
||||
queryString
|
||||
.append("RelayState")
|
||||
.append("=")
|
||||
.append(UriUtils.encode(relayState, StandardCharsets.ISO_8859_1))
|
||||
.append("&");
|
||||
queryString.append("RelayState").append("=")
|
||||
.append(UriUtils.encode(relayState, StandardCharsets.ISO_8859_1)).append("&");
|
||||
}
|
||||
queryString
|
||||
.append("SigAlg")
|
||||
.append("=")
|
||||
.append(UriUtils.encode(algorithmUri, StandardCharsets.ISO_8859_1));
|
||||
queryString.append("SigAlg").append("=").append(UriUtils.encode(algorithmUri, StandardCharsets.ISO_8859_1));
|
||||
|
||||
try {
|
||||
byte[] rawSignature = XMLSigningUtil.signWithURI(
|
||||
credential,
|
||||
algorithmUri,
|
||||
queryString.toString().getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
byte[] rawSignature = XMLSigningUtil.signWithURI(credential, algorithmUri,
|
||||
queryString.toString().getBytes(StandardCharsets.UTF_8));
|
||||
String b64Signature = Saml2Utils.samlEncode(rawSignature);
|
||||
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
@@ -318,8 +293,10 @@ public class OpenSamlAuthenticationRequestFactory implements Saml2Authentication
|
||||
try {
|
||||
Element element = this.marshaller.marshall(authnRequest);
|
||||
return SerializeSupport.nodeToString(element);
|
||||
} catch (MarshallingException e) {
|
||||
}
|
||||
catch (MarshallingException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -31,9 +31,9 @@ import java.util.Map;
|
||||
* @since 5.2.2
|
||||
*/
|
||||
public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal {
|
||||
|
||||
/**
|
||||
* Get the first value of Saml2 token attribute by name
|
||||
*
|
||||
* @param name the name of the attribute
|
||||
* @param <A> the type of the attribute
|
||||
* @return the first attribute value or {@code null} otherwise
|
||||
@@ -47,7 +47,6 @@ public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal {
|
||||
|
||||
/**
|
||||
* Get the Saml2 token attribute by name
|
||||
*
|
||||
* @param name the name of the attribute
|
||||
* @param <A> the type of the attribute
|
||||
* @return the attribute or {@code null} otherwise
|
||||
@@ -60,11 +59,11 @@ public interface Saml2AuthenticatedPrincipal extends AuthenticatedPrincipal {
|
||||
|
||||
/**
|
||||
* Get the Saml2 token attributes
|
||||
*
|
||||
* @return the Saml2 token attributes
|
||||
* @since 5.4
|
||||
*/
|
||||
default Map<String, List<Object>> getAttributes() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-8
@@ -25,23 +25,23 @@ import org.springframework.util.Assert;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* An implementation of an {@link AbstractAuthenticationToken}
|
||||
* that represents an authenticated SAML 2.0 {@link Authentication}.
|
||||
* An implementation of an {@link AbstractAuthenticationToken} that represents an
|
||||
* authenticated SAML 2.0 {@link Authentication}.
|
||||
* <p>
|
||||
* The {@link Authentication} associates valid SAML assertion
|
||||
* data with a Spring Security authentication object
|
||||
* The complete assertion is contained in the object in String format,
|
||||
* {@link Saml2Authentication#getSaml2Response()}
|
||||
* The {@link Authentication} associates valid SAML assertion data with a Spring Security
|
||||
* authentication object The complete assertion is contained in the object in String
|
||||
* format, {@link Saml2Authentication#getSaml2Response()}
|
||||
*
|
||||
* @since 5.2
|
||||
* @see AbstractAuthenticationToken
|
||||
*/
|
||||
public class Saml2Authentication extends AbstractAuthenticationToken {
|
||||
|
||||
private final AuthenticatedPrincipal principal;
|
||||
|
||||
private final String saml2Response;
|
||||
|
||||
public Saml2Authentication(AuthenticatedPrincipal principal,
|
||||
String saml2Response,
|
||||
public Saml2Authentication(AuthenticatedPrincipal principal, String saml2Response,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
super(authorities);
|
||||
Assert.notNull(principal, "principal cannot be null");
|
||||
|
||||
+36
-27
@@ -27,23 +27,23 @@ import org.springframework.util.Assert;
|
||||
* <p>
|
||||
* There are a number of scenarios where an error may occur, for example:
|
||||
* <ul>
|
||||
* <li>The response or assertion request is missing or malformed</li>
|
||||
* <li>Missing or invalid subject</li>
|
||||
* <li>Missing or invalid signatures</li>
|
||||
* <li>The time period validation for the assertion fails</li>
|
||||
* <li>One of the assertion conditions was not met</li>
|
||||
* <li>Decryption failed</li>
|
||||
* <li>Unable to locate a subject identifier, commonly known as username</li>
|
||||
* <li>The response or assertion request is missing or malformed</li>
|
||||
* <li>Missing or invalid subject</li>
|
||||
* <li>Missing or invalid signatures</li>
|
||||
* <li>The time period validation for the assertion fails</li>
|
||||
* <li>One of the assertion conditions was not met</li>
|
||||
* <li>Decryption failed</li>
|
||||
* <li>Unable to locate a subject identifier, commonly known as username</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 5.2
|
||||
*/
|
||||
public class Saml2AuthenticationException extends AuthenticationException {
|
||||
|
||||
private Saml2Error error;
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
|
||||
*
|
||||
* @param error the {@link Saml2Error SAML 2.0 Error}
|
||||
*/
|
||||
public Saml2AuthenticationException(Saml2Error error) {
|
||||
@@ -52,7 +52,6 @@ public class Saml2AuthenticationException extends AuthenticationException {
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
|
||||
*
|
||||
* @param error the {@link Saml2Error SAML 2.0 Error}
|
||||
* @param cause the root cause
|
||||
*/
|
||||
@@ -62,7 +61,6 @@ public class Saml2AuthenticationException extends AuthenticationException {
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
|
||||
*
|
||||
* @param error the {@link Saml2Error SAML 2.0 Error}
|
||||
* @param message the detail message
|
||||
*/
|
||||
@@ -73,7 +71,6 @@ public class Saml2AuthenticationException extends AuthenticationException {
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
|
||||
*
|
||||
* @param error the {@link Saml2Error SAML 2.0 Error}
|
||||
* @param message the detail message
|
||||
* @param cause the root cause
|
||||
@@ -85,57 +82,69 @@ public class Saml2AuthenticationException extends AuthenticationException {
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
|
||||
*
|
||||
* @param error the {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error SAML 2.0 Error}
|
||||
* @deprecated Use {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error} constructor instead
|
||||
* @param error the
|
||||
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error
|
||||
* SAML 2.0 Error}
|
||||
* @deprecated Use
|
||||
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error}
|
||||
* constructor instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Saml2AuthenticationException(org.springframework.security.saml2.provider.service.authentication.Saml2Error error) {
|
||||
public Saml2AuthenticationException(
|
||||
org.springframework.security.saml2.provider.service.authentication.Saml2Error error) {
|
||||
this(error, error.getDescription());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
|
||||
*
|
||||
* @param error the {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error SAML 2.0 Error}
|
||||
* @param error the
|
||||
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error
|
||||
* SAML 2.0 Error}
|
||||
* @param cause the root cause
|
||||
* @deprecated Use {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error} constructor instead
|
||||
* @deprecated Use
|
||||
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error}
|
||||
* constructor instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Saml2AuthenticationException(org.springframework.security.saml2.provider.service.authentication.Saml2Error error, Throwable cause) {
|
||||
public Saml2AuthenticationException(
|
||||
org.springframework.security.saml2.provider.service.authentication.Saml2Error error, Throwable cause) {
|
||||
this(error, cause.getMessage(), cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
|
||||
*
|
||||
* @param error the {@link Saml2Error SAML 2.0 Error}
|
||||
* @param message the detail message
|
||||
* @deprecated Use {@link Saml2Error} constructor instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Saml2AuthenticationException(org.springframework.security.saml2.provider.service.authentication.Saml2Error error, String message) {
|
||||
public Saml2AuthenticationException(
|
||||
org.springframework.security.saml2.provider.service.authentication.Saml2Error error, String message) {
|
||||
super(message);
|
||||
this.setError(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
|
||||
*
|
||||
* @param error the {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error SAML 2.0 Error}
|
||||
* @param error the
|
||||
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error
|
||||
* SAML 2.0 Error}
|
||||
* @param message the detail message
|
||||
* @param cause the root cause
|
||||
* @deprecated Use {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error} constructor instead
|
||||
* @deprecated Use
|
||||
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error}
|
||||
* constructor instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Saml2AuthenticationException(org.springframework.security.saml2.provider.service.authentication.Saml2Error error, String message, Throwable cause) {
|
||||
public Saml2AuthenticationException(
|
||||
org.springframework.security.saml2.provider.service.authentication.Saml2Error error, String message,
|
||||
Throwable cause) {
|
||||
super(message, cause);
|
||||
this.setError(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the associated {@link Saml2Error}
|
||||
*
|
||||
* @return the associated {@link Saml2Error}
|
||||
*/
|
||||
public Saml2Error getSaml2Error() {
|
||||
@@ -144,7 +153,6 @@ public class Saml2AuthenticationException extends AuthenticationException {
|
||||
|
||||
/**
|
||||
* Returns the {@link Saml2Error SAML 2.0 Error}.
|
||||
*
|
||||
* @return the {@link Saml2Error}
|
||||
* @deprecated Use {@link #getSaml2Error()} instead
|
||||
*/
|
||||
@@ -170,4 +178,5 @@ public class Saml2AuthenticationException extends AuthenticationException {
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+37
-38
@@ -25,24 +25,26 @@ import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Data holder for information required to send an {@code AuthNRequest}
|
||||
* from the service provider to the identity provider
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf (line 2031)
|
||||
* Data holder for information required to send an {@code AuthNRequest} from the service
|
||||
* provider to the identity provider
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf
|
||||
* (line 2031)
|
||||
*
|
||||
* @since 5.2
|
||||
* @deprecated use {@link Saml2AuthenticationRequestContext}
|
||||
*/
|
||||
@Deprecated
|
||||
public final class Saml2AuthenticationRequest {
|
||||
|
||||
private final String issuer;
|
||||
|
||||
private final List<Saml2X509Credential> credentials;
|
||||
|
||||
private final String destination;
|
||||
|
||||
private final String assertionConsumerServiceUrl;
|
||||
|
||||
private Saml2AuthenticationRequest(
|
||||
String issuer,
|
||||
String destination,
|
||||
String assertionConsumerServiceUrl,
|
||||
private Saml2AuthenticationRequest(String issuer, String destination, String assertionConsumerServiceUrl,
|
||||
List<Saml2X509Credential> credentials) {
|
||||
Assert.hasText(issuer, "issuer cannot be null");
|
||||
Assert.hasText(destination, "destination cannot be null");
|
||||
@@ -58,10 +60,9 @@ public final class Saml2AuthenticationRequest {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the issuer, the local SP entity ID, for this authentication request.
|
||||
* This property should be used to populate the {@code AuthNRequest.Issuer} XML element.
|
||||
* returns the issuer, the local SP entity ID, for this authentication request. This
|
||||
* property should be used to populate the {@code AuthNRequest.Issuer} XML element.
|
||||
* This value typically is a URI, but can be an arbitrary string.
|
||||
* @return issuer
|
||||
*/
|
||||
@@ -70,8 +71,9 @@ public final class Saml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the destination, the WEB Single Sign On URI, for this authentication request.
|
||||
* This property populates the {@code AuthNRequest#Destination} XML attribute.
|
||||
* returns the destination, the WEB Single Sign On URI, for this authentication
|
||||
* request. This property populates the {@code AuthNRequest#Destination} XML
|
||||
* attribute.
|
||||
* @return destination
|
||||
*/
|
||||
public String getDestination() {
|
||||
@@ -79,9 +81,9 @@ public final class Saml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the desired {@code AssertionConsumerServiceUrl} that this SP wishes to receive the
|
||||
* assertion on. The IDP may or may not honor this request.
|
||||
* This property populates the {@code AuthNRequest#AssertionConsumerServiceURL} XML attribute.
|
||||
* Returns the desired {@code AssertionConsumerServiceUrl} that this SP wishes to
|
||||
* receive the assertion on. The IDP may or may not honor this request. This property
|
||||
* populates the {@code AuthNRequest#AssertionConsumerServiceURL} XML attribute.
|
||||
* @return the AssertionConsumerServiceURL value
|
||||
*/
|
||||
public String getAssertionConsumerServiceUrl() {
|
||||
@@ -89,7 +91,8 @@ public final class Saml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of credentials that can be used to sign the {@code AuthNRequest} object
|
||||
* Returns a list of credentials that can be used to sign the {@code AuthNRequest}
|
||||
* object
|
||||
* @return signing credentials
|
||||
*/
|
||||
public List<Saml2X509Credential> getCredentials() {
|
||||
@@ -97,8 +100,7 @@ public final class Saml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link Saml2AuthenticationRequest}.
|
||||
* returns a builder object
|
||||
* A builder for {@link Saml2AuthenticationRequest}. returns a builder object
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
@@ -106,25 +108,25 @@ public final class Saml2AuthenticationRequest {
|
||||
|
||||
/**
|
||||
* A builder for {@link Saml2AuthenticationRequest}.
|
||||
* @param context a context object to copy values from.
|
||||
* returns a builder object
|
||||
* @param context a context object to copy values from. returns a builder object
|
||||
*/
|
||||
public static Builder withAuthenticationRequestContext(Saml2AuthenticationRequestContext context) {
|
||||
return new Builder()
|
||||
.assertionConsumerServiceUrl(context.getAssertionConsumerServiceUrl())
|
||||
.issuer(context.getIssuer())
|
||||
.destination(context.getDestination())
|
||||
.credentials(c -> c.addAll(context.getRelyingPartyRegistration().getCredentials()))
|
||||
;
|
||||
return new Builder().assertionConsumerServiceUrl(context.getAssertionConsumerServiceUrl())
|
||||
.issuer(context.getIssuer()).destination(context.getDestination())
|
||||
.credentials(c -> c.addAll(context.getRelyingPartyRegistration().getCredentials()));
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for {@link Saml2AuthenticationRequest}.
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private String issuer;
|
||||
|
||||
private List<Saml2X509Credential> credentials = new LinkedList<>();
|
||||
|
||||
private String destination;
|
||||
|
||||
private String assertionConsumerServiceUrl;
|
||||
|
||||
private Builder() {
|
||||
@@ -141,11 +143,9 @@ public final class Saml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the collection of {@link Saml2X509Credential} credentials
|
||||
* used in communication between IDP and SP, specifically signing the
|
||||
* authentication request.
|
||||
* For example:
|
||||
* <code>
|
||||
* Modifies the collection of {@link Saml2X509Credential} credentials used in
|
||||
* communication between IDP and SP, specifically signing the authentication
|
||||
* request. For example: <code>
|
||||
* Saml2X509Credential credential = ...;
|
||||
* return Saml2AuthenticationRequest.withLocalSpEntityId("id")
|
||||
* .credentials(c -> c.add(credential))
|
||||
@@ -161,7 +161,8 @@ public final class Saml2AuthenticationRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Destination for the authentication request. Typically the {@code Service Provider EntityID}
|
||||
* Sets the Destination for the authentication request. Typically the
|
||||
* {@code Service Provider EntityID}
|
||||
* @param destination - a required value
|
||||
* @return this {@code Builder}
|
||||
*/
|
||||
@@ -187,12 +188,10 @@ public final class Saml2AuthenticationRequest {
|
||||
* @throws {@link IllegalArgumentException} if a required property is not set
|
||||
*/
|
||||
public Saml2AuthenticationRequest build() {
|
||||
return new Saml2AuthenticationRequest(
|
||||
this.issuer,
|
||||
this.destination,
|
||||
this.assertionConsumerServiceUrl,
|
||||
this.credentials
|
||||
);
|
||||
return new Saml2AuthenticationRequest(this.issuer, this.destination, this.assertionConsumerServiceUrl,
|
||||
this.credentials);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+31
-24
@@ -20,9 +20,9 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Data holder for information required to create an {@code AuthNRequest}
|
||||
* to be sent from the service provider to the identity provider
|
||||
* <a href="https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf">
|
||||
* Data holder for information required to create an {@code AuthNRequest} to be sent from
|
||||
* the service provider to the identity provider <a href=
|
||||
* "https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf">
|
||||
* Assertions and Protocols for SAML 2 (line 2031)</a>
|
||||
*
|
||||
* @see Saml2AuthenticationRequestFactory#createPostAuthenticationRequest(Saml2AuthenticationRequestContext)
|
||||
@@ -30,16 +30,17 @@ import org.springframework.util.Assert;
|
||||
* @since 5.3
|
||||
*/
|
||||
public class Saml2AuthenticationRequestContext {
|
||||
|
||||
private final RelyingPartyRegistration relyingPartyRegistration;
|
||||
|
||||
private final String issuer;
|
||||
|
||||
private final String assertionConsumerServiceUrl;
|
||||
|
||||
private final String relayState;
|
||||
|
||||
protected Saml2AuthenticationRequestContext(
|
||||
RelyingPartyRegistration relyingPartyRegistration,
|
||||
String issuer,
|
||||
String assertionConsumerServiceUrl,
|
||||
String relayState) {
|
||||
protected Saml2AuthenticationRequestContext(RelyingPartyRegistration relyingPartyRegistration, String issuer,
|
||||
String assertionConsumerServiceUrl, String relayState) {
|
||||
Assert.hasText(issuer, "issuer cannot be null or empty");
|
||||
Assert.notNull(relyingPartyRegistration, "relyingPartyRegistration cannot be null");
|
||||
Assert.hasText(assertionConsumerServiceUrl, "spAssertionConsumerServiceUrl cannot be null or empty");
|
||||
@@ -50,7 +51,8 @@ public class Saml2AuthenticationRequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link RelyingPartyRegistration} configuration for which the AuthNRequest is intended for.
|
||||
* Returns the {@link RelyingPartyRegistration} configuration for which the
|
||||
* AuthNRequest is intended for.
|
||||
* @return the {@link RelyingPartyRegistration} configuration
|
||||
*/
|
||||
public RelyingPartyRegistration getRelyingPartyRegistration() {
|
||||
@@ -59,8 +61,8 @@ public class Saml2AuthenticationRequestContext {
|
||||
|
||||
/**
|
||||
* Returns the {@code Issuer} value to be used in the {@code AuthNRequest} object.
|
||||
* This property should be used to populate the {@code AuthNRequest.Issuer} XML element.
|
||||
* This value typically is a URI, but can be an arbitrary string.
|
||||
* This property should be used to populate the {@code AuthNRequest.Issuer} XML
|
||||
* element. This value typically is a URI, but can be an arbitrary string.
|
||||
* @return the Issuer value
|
||||
*/
|
||||
public String getIssuer() {
|
||||
@@ -68,9 +70,9 @@ public class Saml2AuthenticationRequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the desired {@code AssertionConsumerServiceUrl} that this SP wishes to receive the
|
||||
* assertion on. The IDP may or may not honor this request.
|
||||
* This property populates the {@code AuthNRequest.AssertionConsumerServiceURL} XML attribute.
|
||||
* Returns the desired {@code AssertionConsumerServiceUrl} that this SP wishes to
|
||||
* receive the assertion on. The IDP may or may not honor this request. This property
|
||||
* populates the {@code AuthNRequest.AssertionConsumerServiceURL} XML attribute.
|
||||
* @return the AssertionConsumerServiceURL value
|
||||
*/
|
||||
public String getAssertionConsumerServiceUrl() {
|
||||
@@ -86,8 +88,9 @@ public class Saml2AuthenticationRequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Destination}, the WEB Single Sign On URI, for this authentication request.
|
||||
* This property can also populate the {@code AuthNRequest.Destination} XML attribute.
|
||||
* Returns the {@code Destination}, the WEB Single Sign On URI, for this
|
||||
* authentication request. This property can also populate the
|
||||
* {@code AuthNRequest.Destination} XML attribute.
|
||||
* @return the Destination value
|
||||
*/
|
||||
public String getDestination() {
|
||||
@@ -106,9 +109,13 @@ public class Saml2AuthenticationRequestContext {
|
||||
* A builder for {@link Saml2AuthenticationRequestContext}.
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private String issuer;
|
||||
|
||||
private String assertionConsumerServiceUrl;
|
||||
|
||||
private String relayState;
|
||||
|
||||
private RelyingPartyRegistration relyingPartyRegistration;
|
||||
|
||||
private Builder() {
|
||||
@@ -125,7 +132,8 @@ public class Saml2AuthenticationRequestContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link RelyingPartyRegistration} used to build the authentication request.
|
||||
* Sets the {@link RelyingPartyRegistration} used to build the authentication
|
||||
* request.
|
||||
* @param relyingPartyRegistration - a required value
|
||||
* @return this {@code Builder}
|
||||
*/
|
||||
@@ -147,7 +155,8 @@ public class Saml2AuthenticationRequestContext {
|
||||
|
||||
/**
|
||||
* Sets the {@code RelayState} parameter that will accompany this AuthNRequest
|
||||
* @param relayState the relay state value, unencoded. if null or empty, the parameter will be removed from the map.
|
||||
* @param relayState the relay state value, unencoded. if null or empty, the
|
||||
* parameter will be removed from the map.
|
||||
* @return this object
|
||||
*/
|
||||
public Builder relayState(String relayState) {
|
||||
@@ -161,12 +170,10 @@ public class Saml2AuthenticationRequestContext {
|
||||
* @throws {@link IllegalArgumentException} if a required property is not set
|
||||
*/
|
||||
public Saml2AuthenticationRequestContext build() {
|
||||
return new Saml2AuthenticationRequestContext(
|
||||
this.relyingPartyRegistration,
|
||||
this.issuer,
|
||||
this.assertionConsumerServiceUrl,
|
||||
this.relayState
|
||||
);
|
||||
return new Saml2AuthenticationRequestContext(this.relyingPartyRegistration, this.issuer,
|
||||
this.assertionConsumerServiceUrl, this.relayState);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+54
-54
@@ -27,9 +27,9 @@ import static org.springframework.security.saml2.provider.service.authentication
|
||||
import static org.springframework.security.saml2.provider.service.authentication.Saml2Utils.samlEncode;
|
||||
|
||||
/**
|
||||
* Component that generates AuthenticationRequest, <code>samlp:AuthnRequestType</code> XML, and accompanying
|
||||
* signature data.
|
||||
* as defined by https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf
|
||||
* Component that generates AuthenticationRequest, <code>samlp:AuthnRequestType</code>
|
||||
* XML, and accompanying signature data. as defined by
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf
|
||||
* Page 50, Line 2147
|
||||
*
|
||||
* @since 5.2
|
||||
@@ -37,81 +37,81 @@ import static org.springframework.security.saml2.provider.service.authentication
|
||||
public interface Saml2AuthenticationRequestFactory {
|
||||
|
||||
/**
|
||||
* Creates an authentication request from the Service Provider, sp, to the Identity Provider, idp.
|
||||
* The authentication result is an XML string that may be signed, encrypted, both or neither.
|
||||
* This method only returns the {@code SAMLRequest} string for the request, and for a complete
|
||||
* set of data parameters please use {@link #createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext)}
|
||||
* or {@link #createPostAuthenticationRequest(Saml2AuthenticationRequestContext)}
|
||||
*
|
||||
* @param request information about the identity provider,
|
||||
* the recipient of this authentication request and accompanying data
|
||||
* @return XML data in the format of a String. This data may be signed, encrypted, both signed and encrypted with the
|
||||
* signature embedded in the XML or neither signed and encrypted
|
||||
* Creates an authentication request from the Service Provider, sp, to the Identity
|
||||
* Provider, idp. The authentication result is an XML string that may be signed,
|
||||
* encrypted, both or neither. This method only returns the {@code SAMLRequest} string
|
||||
* for the request, and for a complete set of data parameters please use
|
||||
* {@link #createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext)} or
|
||||
* {@link #createPostAuthenticationRequest(Saml2AuthenticationRequestContext)}
|
||||
* @param request information about the identity provider, the recipient of this
|
||||
* authentication request and accompanying data
|
||||
* @return XML data in the format of a String. This data may be signed, encrypted,
|
||||
* both signed and encrypted with the signature embedded in the XML or neither signed
|
||||
* and encrypted
|
||||
* @throws Saml2Exception when a SAML library exception occurs
|
||||
* @since 5.2
|
||||
* @deprecated please use {@link #createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext)}
|
||||
* or {@link #createPostAuthenticationRequest(Saml2AuthenticationRequestContext)}
|
||||
* This method will be removed in future versions of Spring Security
|
||||
* @deprecated please use
|
||||
* {@link #createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext)} or
|
||||
* {@link #createPostAuthenticationRequest(Saml2AuthenticationRequestContext)} This
|
||||
* method will be removed in future versions of Spring Security
|
||||
*/
|
||||
@Deprecated
|
||||
String createAuthenticationRequest(Saml2AuthenticationRequest request);
|
||||
|
||||
/**
|
||||
* Creates all the necessary AuthNRequest parameters for a REDIRECT binding.
|
||||
* If the {@link Saml2AuthenticationRequestContext} doesn't contain any {@link Saml2X509CredentialType#SIGNING} credentials
|
||||
* the result will not contain any signatures.
|
||||
* The data set will be signed and encoded for REDIRECT binding including the DEFLATE encoding.
|
||||
* It will contain the following parameters to be sent as part of the query string:
|
||||
* {@code SAMLRequest, RelayState, SigAlg, Signature}.
|
||||
* <i>The default implementation, for sake of backwards compatibility, of this method returns the
|
||||
* SAMLRequest message with an XML signature embedded, that should only be used for the{@link Saml2MessageBinding#POST}
|
||||
* binding, but works over {@link Saml2MessageBinding#POST} with most providers.</i>
|
||||
* @param context - information about the identity provider, the recipient of this authentication request and
|
||||
* accompanying data
|
||||
* @return a {@link Saml2RedirectAuthenticationRequest} object with applicable http parameters
|
||||
* necessary to make the AuthNRequest over a POST or REDIRECT binding.
|
||||
* All parameters will be SAML encoded/deflated, but escaped, ie URI encoded or encoded for Form Data.
|
||||
* Creates all the necessary AuthNRequest parameters for a REDIRECT binding. If the
|
||||
* {@link Saml2AuthenticationRequestContext} doesn't contain any
|
||||
* {@link Saml2X509CredentialType#SIGNING} credentials the result will not contain any
|
||||
* signatures. The data set will be signed and encoded for REDIRECT binding including
|
||||
* the DEFLATE encoding. It will contain the following parameters to be sent as part
|
||||
* of the query string: {@code SAMLRequest, RelayState, SigAlg, Signature}. <i>The
|
||||
* default implementation, for sake of backwards compatibility, of this method returns
|
||||
* the SAMLRequest message with an XML signature embedded, that should only be used
|
||||
* for the{@link Saml2MessageBinding#POST} binding, but works over
|
||||
* {@link Saml2MessageBinding#POST} with most providers.</i>
|
||||
* @param context - information about the identity provider, the recipient of this
|
||||
* authentication request and accompanying data
|
||||
* @return a {@link Saml2RedirectAuthenticationRequest} object with applicable http
|
||||
* parameters necessary to make the AuthNRequest over a POST or REDIRECT binding. All
|
||||
* parameters will be SAML encoded/deflated, but escaped, ie URI encoded or encoded
|
||||
* for Form Data.
|
||||
* @throws Saml2Exception when a SAML library exception occurs
|
||||
* @since 5.3
|
||||
*/
|
||||
default Saml2RedirectAuthenticationRequest createRedirectAuthenticationRequest(
|
||||
Saml2AuthenticationRequestContext context
|
||||
) {
|
||||
//backwards compatible with 5.2.x settings
|
||||
Saml2AuthenticationRequestContext context) {
|
||||
// backwards compatible with 5.2.x settings
|
||||
Saml2AuthenticationRequest.Builder resultBuilder = withAuthenticationRequestContext(context);
|
||||
String samlRequest = createAuthenticationRequest(resultBuilder.build());
|
||||
samlRequest = samlEncode(samlDeflate(samlRequest));
|
||||
return Saml2RedirectAuthenticationRequest.withAuthenticationRequestContext(context)
|
||||
.samlRequest(samlRequest)
|
||||
return Saml2RedirectAuthenticationRequest.withAuthenticationRequestContext(context).samlRequest(samlRequest)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates all the necessary AuthNRequest parameters for a POST binding.
|
||||
* If the {@link Saml2AuthenticationRequestContext} doesn't contain any {@link Saml2X509CredentialType#SIGNING} credentials
|
||||
* the result will not contain any signatures.
|
||||
* The data set will be signed and encoded for POST binding and if applicable signed with XML signatures.
|
||||
* will contain the following parameters to be sent as part of the form data: {@code SAMLRequest, RelayState}.
|
||||
* <i>The default implementation of this method returns the SAMLRequest message with an XML signature embedded,
|
||||
* that should only be used for the {@link Saml2MessageBinding#POST} binding.</i>
|
||||
* @param context - information about the identity provider, the recipient of this authentication request and
|
||||
* accompanying data
|
||||
* @return a {@link Saml2PostAuthenticationRequest} object with applicable http parameters
|
||||
* necessary to make the AuthNRequest over a POST binding.
|
||||
* All parameters will be SAML encoded but not escaped for Form Data.
|
||||
* Creates all the necessary AuthNRequest parameters for a POST binding. If the
|
||||
* {@link Saml2AuthenticationRequestContext} doesn't contain any
|
||||
* {@link Saml2X509CredentialType#SIGNING} credentials the result will not contain any
|
||||
* signatures. The data set will be signed and encoded for POST binding and if
|
||||
* applicable signed with XML signatures. will contain the following parameters to be
|
||||
* sent as part of the form data: {@code SAMLRequest, RelayState}. <i>The default
|
||||
* implementation of this method returns the SAMLRequest message with an XML signature
|
||||
* embedded, that should only be used for the {@link Saml2MessageBinding#POST}
|
||||
* binding.</i>
|
||||
* @param context - information about the identity provider, the recipient of this
|
||||
* authentication request and accompanying data
|
||||
* @return a {@link Saml2PostAuthenticationRequest} object with applicable http
|
||||
* parameters necessary to make the AuthNRequest over a POST binding. All parameters
|
||||
* will be SAML encoded but not escaped for Form Data.
|
||||
* @throws Saml2Exception when a SAML library exception occurs
|
||||
* @since 5.3
|
||||
*/
|
||||
default Saml2PostAuthenticationRequest createPostAuthenticationRequest(
|
||||
Saml2AuthenticationRequestContext context
|
||||
) {
|
||||
//backwards compatible with 5.2.x settings
|
||||
default Saml2PostAuthenticationRequest createPostAuthenticationRequest(Saml2AuthenticationRequestContext context) {
|
||||
// backwards compatible with 5.2.x settings
|
||||
Saml2AuthenticationRequest.Builder resultBuilder = withAuthenticationRequestContext(context);
|
||||
String samlRequest = createAuthenticationRequest(resultBuilder.build());
|
||||
samlRequest = samlEncode(samlRequest.getBytes(StandardCharsets.UTF_8));
|
||||
return Saml2PostAuthenticationRequest.withAuthenticationRequestContext(context)
|
||||
.samlRequest(samlRequest)
|
||||
return Saml2PostAuthenticationRequest.withAuthenticationRequestContext(context).samlRequest(samlRequest)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+29
-27
@@ -27,8 +27,8 @@ import org.springframework.util.Assert;
|
||||
import static org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.withRegistrationId;
|
||||
|
||||
/**
|
||||
* Represents an incoming SAML 2.0 response containing an assertion that has not been validated.
|
||||
* {@link Saml2AuthenticationToken#isAuthenticated()} will always return false.
|
||||
* Represents an incoming SAML 2.0 response containing an assertion that has not been
|
||||
* validated. {@link Saml2AuthenticationToken#isAuthenticated()} will always return false.
|
||||
*
|
||||
* @since 5.2
|
||||
* @author Filip Hanik
|
||||
@@ -37,23 +37,23 @@ import static org.springframework.security.saml2.provider.service.registration.R
|
||||
public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
private final RelyingPartyRegistration relyingPartyRegistration;
|
||||
|
||||
private final String saml2Response;
|
||||
|
||||
/**
|
||||
* Creates a {@link Saml2AuthenticationToken} with the provided parameters
|
||||
*
|
||||
* Note that the given {@link RelyingPartyRegistration} should have all its
|
||||
* templates resolved at this point. See
|
||||
* Note that the given {@link RelyingPartyRegistration} should have all its templates
|
||||
* resolved at this point. See
|
||||
* {@link org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter}
|
||||
* for an example of performing that resolution.
|
||||
*
|
||||
* @param relyingPartyRegistration the resolved {@link RelyingPartyRegistration} to use
|
||||
* @param relyingPartyRegistration the resolved {@link RelyingPartyRegistration} to
|
||||
* use
|
||||
* @param saml2Response the SAML 2.0 response to authenticate
|
||||
*
|
||||
* @since 5.4
|
||||
*/
|
||||
public Saml2AuthenticationToken(RelyingPartyRegistration relyingPartyRegistration,
|
||||
String saml2Response) {
|
||||
public Saml2AuthenticationToken(RelyingPartyRegistration relyingPartyRegistration, String saml2Response) {
|
||||
|
||||
super(Collections.emptyList());
|
||||
Assert.notNull(relyingPartyRegistration, "relyingPartyRegistration cannot be null");
|
||||
@@ -65,26 +65,23 @@ public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
/**
|
||||
* Creates an authentication token from an incoming SAML 2 Response object
|
||||
* @param saml2Response inflated and decoded XML representation of the SAML 2 Response
|
||||
* @param recipientUri the URL that the SAML 2 Response was received at. Used for validation
|
||||
* @param recipientUri the URL that the SAML 2 Response was received at. Used for
|
||||
* validation
|
||||
* @param idpEntityId the entity ID of the asserting entity
|
||||
* @param localSpEntityId the configured local SP, the relying party, entity ID
|
||||
* @param credentials the credentials configured for signature verification and decryption
|
||||
* @deprecated Use {@link Saml2AuthenticationToken(RelyingPartyRegistration, String)} instead
|
||||
* @param credentials the credentials configured for signature verification and
|
||||
* decryption
|
||||
* @deprecated Use {@link Saml2AuthenticationToken(RelyingPartyRegistration, String)}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Saml2AuthenticationToken(String saml2Response,
|
||||
String recipientUri,
|
||||
String idpEntityId,
|
||||
String localSpEntityId,
|
||||
List<Saml2X509Credential> credentials) {
|
||||
public Saml2AuthenticationToken(String saml2Response, String recipientUri, String idpEntityId,
|
||||
String localSpEntityId, List<Saml2X509Credential> credentials) {
|
||||
super(null);
|
||||
this.relyingPartyRegistration = withRegistrationId(idpEntityId)
|
||||
.entityId(localSpEntityId)
|
||||
.assertionConsumerServiceLocation(recipientUri)
|
||||
.credentials(c -> c.addAll(credentials))
|
||||
.assertingPartyDetails(assertingParty -> assertingParty
|
||||
.entityId(idpEntityId)
|
||||
.singleSignOnServiceLocation(idpEntityId))
|
||||
this.relyingPartyRegistration = withRegistrationId(idpEntityId).entityId(localSpEntityId)
|
||||
.assertionConsumerServiceLocation(recipientUri).credentials(c -> c.addAll(credentials))
|
||||
.assertingPartyDetails(
|
||||
assertingParty -> assertingParty.entityId(idpEntityId).singleSignOnServiceLocation(idpEntityId))
|
||||
.build();
|
||||
this.saml2Response = saml2Response;
|
||||
}
|
||||
@@ -109,7 +106,6 @@ public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
/**
|
||||
* Get the resolved {@link RelyingPartyRegistration} associated with the request
|
||||
*
|
||||
* @return the resolved {@link RelyingPartyRegistration}
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -128,7 +124,9 @@ public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
/**
|
||||
* Returns the URI that the SAML 2 Response object came in on
|
||||
* @return URI as a string
|
||||
* @deprecated Use {@link #getRelyingPartyRegistration().getAssertionConsumerServiceLocation()} instead
|
||||
* @deprecated Use
|
||||
* {@link #getRelyingPartyRegistration().getAssertionConsumerServiceLocation()}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getRecipientUri() {
|
||||
@@ -148,7 +146,8 @@ public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
/**
|
||||
* Returns all the credentials associated with the relying party configuraiton
|
||||
* @return
|
||||
* @deprecated Get the credentials through {@link #getRelyingPartyRegistration()} instead
|
||||
* @deprecated Get the credentials through {@link #getRelyingPartyRegistration()}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public List<Saml2X509Credential> getX509Credentials() {
|
||||
@@ -176,10 +175,13 @@ public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
|
||||
/**
|
||||
* Returns the configured IDP, asserting party, entity ID
|
||||
* @return a string representing the entity ID
|
||||
* @deprecated Use {@link #getRelyingPartyRegistration().getAssertingPartyDetails().getEntityId()} instead
|
||||
* @deprecated Use
|
||||
* {@link #getRelyingPartyRegistration().getAssertingPartyDetails().getEntityId()}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public String getIdpEntityId() {
|
||||
return this.relyingPartyRegistration.getAssertingPartyDetails().getEntityId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-8
@@ -24,22 +24,23 @@ import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
* A representation of an SAML 2.0 Error.
|
||||
*
|
||||
* <p>
|
||||
* At a minimum, an error response will contain an error code.
|
||||
* The commonly used error code are defined in this class
|
||||
* or a new codes can be defined in the future as arbitrary strings.
|
||||
* At a minimum, an error response will contain an error code. The commonly used error
|
||||
* code are defined in this class or a new codes can be defined in the future as arbitrary
|
||||
* strings.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.2
|
||||
* @deprecated Use {@link org.springframework.security.saml2.core.Saml2Error} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class Saml2Error implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
private final org.springframework.security.saml2.core.Saml2Error error;
|
||||
|
||||
/**
|
||||
* Constructs a {@code Saml2Error} using the provided parameters.
|
||||
*
|
||||
* @param errorCode the error code
|
||||
* @param description the error description
|
||||
*/
|
||||
@@ -49,7 +50,6 @@ public class Saml2Error implements Serializable {
|
||||
|
||||
/**
|
||||
* Returns the error code.
|
||||
*
|
||||
* @return the error code
|
||||
*/
|
||||
public final String getErrorCode() {
|
||||
@@ -58,7 +58,6 @@ public class Saml2Error implements Serializable {
|
||||
|
||||
/**
|
||||
* Returns the error description.
|
||||
*
|
||||
* @return the error description
|
||||
*/
|
||||
public final String getDescription() {
|
||||
@@ -67,7 +66,7 @@ public class Saml2Error implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.getErrorCode() + "] " +
|
||||
(this.getDescription() != null ? this.getDescription() : "");
|
||||
return "[" + this.getErrorCode() + "] " + (this.getDescription() != null ? this.getDescription() : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+38
-34
@@ -24,80 +24,84 @@ package org.springframework.security.saml2.provider.service.authentication;
|
||||
*/
|
||||
@Deprecated
|
||||
public interface Saml2ErrorCodes {
|
||||
|
||||
/**
|
||||
* SAML Data does not represent a SAML 2 Response object.
|
||||
* A valid XML object was received, but that object was not a
|
||||
* SAML 2 Response object of type {@code ResponseType} per specification
|
||||
* SAML Data does not represent a SAML 2 Response object. A valid XML object was
|
||||
* received, but that object was not a SAML 2 Response object of type
|
||||
* {@code ResponseType} per specification
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=46
|
||||
*/
|
||||
String UNKNOWN_RESPONSE_CLASS = org.springframework.security.saml2.core.Saml2ErrorCodes.UNKNOWN_RESPONSE_CLASS;
|
||||
|
||||
/**
|
||||
* The response data is malformed or incomplete.
|
||||
* An invalid XML object was received, and XML unmarshalling failed.
|
||||
* The response data is malformed or incomplete. An invalid XML object was received,
|
||||
* and XML unmarshalling failed.
|
||||
*/
|
||||
String MALFORMED_RESPONSE_DATA = org.springframework.security.saml2.core.Saml2ErrorCodes.MALFORMED_RESPONSE_DATA;
|
||||
|
||||
/**
|
||||
* Response destination does not match the request URL.
|
||||
* A SAML 2 response object was received at a URL that
|
||||
* did not match the URL stored in the {code Destination} attribute
|
||||
* in the Response object.
|
||||
* Response destination does not match the request URL. A SAML 2 response object was
|
||||
* received at a URL that did not match the URL stored in the {code Destination}
|
||||
* attribute in the Response object.
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=38
|
||||
*/
|
||||
String INVALID_DESTINATION = org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_DESTINATION;
|
||||
|
||||
/**
|
||||
* The assertion was not valid.
|
||||
* The assertion used for authentication failed validation.
|
||||
* Details around the failure will be present in the error description.
|
||||
* The assertion was not valid. The assertion used for authentication failed
|
||||
* validation. Details around the failure will be present in the error description.
|
||||
*/
|
||||
String INVALID_ASSERTION = org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_ASSERTION;
|
||||
|
||||
/**
|
||||
* The signature of response or assertion was invalid.
|
||||
* Either the response or the assertion was missing a signature
|
||||
* or the signature could not be verified using the system's
|
||||
* configured credentials. Most commonly the IDP's
|
||||
* X509 certificate.
|
||||
* The signature of response or assertion was invalid. Either the response or the
|
||||
* assertion was missing a signature or the signature could not be verified using the
|
||||
* system's configured credentials. Most commonly the IDP's X509 certificate.
|
||||
*/
|
||||
String INVALID_SIGNATURE = org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_SIGNATURE;
|
||||
|
||||
/**
|
||||
* The assertion did not contain a subject element.
|
||||
* The subject element, type SubjectType, contains
|
||||
* a {@code NameID} or an {@code EncryptedID} that is used
|
||||
* to assign the authenticated principal an identifier,
|
||||
* typically a username.
|
||||
* The assertion did not contain a subject element. The subject element, type
|
||||
* SubjectType, contains a {@code NameID} or an {@code EncryptedID} that is used to
|
||||
* assign the authenticated principal an identifier, typically a username.
|
||||
*
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=18
|
||||
*/
|
||||
String SUBJECT_NOT_FOUND = org.springframework.security.saml2.core.Saml2ErrorCodes.SUBJECT_NOT_FOUND;
|
||||
|
||||
/**
|
||||
* The subject did not contain a user identifier
|
||||
* The assertion contained a subject element, but the subject
|
||||
* element did not have a {@code NameID} or {@code EncryptedID}
|
||||
* element
|
||||
* The subject did not contain a user identifier The assertion contained a subject
|
||||
* element, but the subject element did not have a {@code NameID} or
|
||||
* {@code EncryptedID} element
|
||||
*
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=18
|
||||
*/
|
||||
String USERNAME_NOT_FOUND = org.springframework.security.saml2.core.Saml2ErrorCodes.USERNAME_NOT_FOUND;
|
||||
|
||||
/**
|
||||
* The system failed to decrypt an assertion or a name identifier.
|
||||
* This error code will be thrown if the decryption of either a
|
||||
* {@code EncryptedAssertion} or {@code EncryptedID} fails.
|
||||
* The system failed to decrypt an assertion or a name identifier. This error code
|
||||
* will be thrown if the decryption of either a {@code EncryptedAssertion} or
|
||||
* {@code EncryptedID} fails.
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=17
|
||||
*/
|
||||
String DECRYPTION_ERROR = org.springframework.security.saml2.core.Saml2ErrorCodes.DECRYPTION_ERROR;
|
||||
|
||||
/**
|
||||
* An Issuer element contained a value that didn't
|
||||
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=15
|
||||
*/
|
||||
String INVALID_ISSUER = org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_ISSUER;
|
||||
|
||||
/**
|
||||
* An error happened during validation.
|
||||
* Used when internal, non classified, errors are caught during the
|
||||
* authentication process.
|
||||
* An error happened during validation. Used when internal, non classified, errors are
|
||||
* caught during the authentication process.
|
||||
*/
|
||||
String INTERNAL_VALIDATION_ERROR = org.springframework.security.saml2.core.Saml2ErrorCodes.INTERNAL_VALIDATION_ERROR;
|
||||
|
||||
/**
|
||||
* The relying party registration was not found.
|
||||
* The registration ID did not correspond to any relying party registration.
|
||||
* The relying party registration was not found. The registration ID did not
|
||||
* correspond to any relying party registration.
|
||||
*/
|
||||
String RELYING_PARTY_REGISTRATION_NOT_FOUND = org.springframework.security.saml2.core.Saml2ErrorCodes.RELYING_PARTY_REGISTRATION_NOT_FOUND;
|
||||
|
||||
}
|
||||
|
||||
+14
-21
@@ -21,19 +21,17 @@ import org.springframework.security.saml2.provider.service.registration.Saml2Mes
|
||||
import static org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding.POST;
|
||||
|
||||
/**
|
||||
* Data holder for information required to send an {@code AuthNRequest} over a POST binding
|
||||
* from the service provider to the identity provider
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf (line 2031)
|
||||
* Data holder for information required to send an {@code AuthNRequest} over a POST
|
||||
* binding from the service provider to the identity provider
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf
|
||||
* (line 2031)
|
||||
*
|
||||
* @see Saml2AuthenticationRequestFactory
|
||||
* @since 5.3
|
||||
*/
|
||||
public class Saml2PostAuthenticationRequest extends AbstractSaml2AuthenticationRequest {
|
||||
|
||||
private Saml2PostAuthenticationRequest(
|
||||
String samlRequest,
|
||||
String relayState,
|
||||
String authenticationRequestUri) {
|
||||
private Saml2PostAuthenticationRequest(String samlRequest, String relayState, String authenticationRequestUri) {
|
||||
super(samlRequest, relayState, authenticationRequestUri);
|
||||
}
|
||||
|
||||
@@ -46,17 +44,16 @@ public class Saml2PostAuthenticationRequest extends AbstractSaml2AuthenticationR
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link Builder} from a {@link Saml2AuthenticationRequestContext} object.
|
||||
* By default the {@link Saml2PostAuthenticationRequest#getAuthenticationRequestUri()} will be set to the
|
||||
* {@link Saml2AuthenticationRequestContext#getDestination()} value.
|
||||
* @param context input providing {@code Destination}, {@code RelayState}, and {@code Issuer} objects.
|
||||
* Constructs a {@link Builder} from a {@link Saml2AuthenticationRequestContext}
|
||||
* object. By default the
|
||||
* {@link Saml2PostAuthenticationRequest#getAuthenticationRequestUri()} will be set to
|
||||
* the {@link Saml2AuthenticationRequestContext#getDestination()} value.
|
||||
* @param context input providing {@code Destination}, {@code RelayState}, and
|
||||
* {@code Issuer} objects.
|
||||
* @return a modifiable builder object
|
||||
*/
|
||||
public static Builder withAuthenticationRequestContext(Saml2AuthenticationRequestContext context) {
|
||||
return new Builder()
|
||||
.authenticationRequestUri(context.getDestination())
|
||||
.relayState(context.getRelayState())
|
||||
;
|
||||
return new Builder().authenticationRequestUri(context.getDestination()).relayState(context.getRelayState());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,13 +70,9 @@ public class Saml2PostAuthenticationRequest extends AbstractSaml2AuthenticationR
|
||||
* @return an immutable {@link Saml2PostAuthenticationRequest} object.
|
||||
*/
|
||||
public Saml2PostAuthenticationRequest build() {
|
||||
return new Saml2PostAuthenticationRequest(
|
||||
this.samlRequest,
|
||||
this.relayState,
|
||||
this.authenticationRequestUri
|
||||
);
|
||||
return new Saml2PostAuthenticationRequest(this.samlRequest, this.relayState, this.authenticationRequestUri);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+18
-25
@@ -21,9 +21,10 @@ import org.springframework.security.saml2.provider.service.registration.Saml2Mes
|
||||
import static org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding.REDIRECT;
|
||||
|
||||
/**
|
||||
* Data holder for information required to send an {@code AuthNRequest} over a REDIRECT binding
|
||||
* from the service provider to the identity provider
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf (line 2031)
|
||||
* Data holder for information required to send an {@code AuthNRequest} over a REDIRECT
|
||||
* binding from the service provider to the identity provider
|
||||
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf
|
||||
* (line 2031)
|
||||
*
|
||||
* @see Saml2AuthenticationRequestFactory
|
||||
* @since 5.3
|
||||
@@ -31,13 +32,10 @@ import static org.springframework.security.saml2.provider.service.registration.S
|
||||
public class Saml2RedirectAuthenticationRequest extends AbstractSaml2AuthenticationRequest {
|
||||
|
||||
private final String sigAlg;
|
||||
|
||||
private final String signature;
|
||||
|
||||
private Saml2RedirectAuthenticationRequest(
|
||||
String samlRequest,
|
||||
String sigAlg,
|
||||
String signature,
|
||||
String relayState,
|
||||
private Saml2RedirectAuthenticationRequest(String samlRequest, String sigAlg, String signature, String relayState,
|
||||
String authenticationRequestUri) {
|
||||
super(samlRequest, relayState, authenticationRequestUri);
|
||||
this.sigAlg = sigAlg;
|
||||
@@ -61,7 +59,7 @@ public class Saml2RedirectAuthenticationRequest extends AbstractSaml2Authenticat
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link Saml2MessageBinding#REDIRECT}
|
||||
* @return {@link Saml2MessageBinding#REDIRECT}
|
||||
*/
|
||||
@Override
|
||||
public Saml2MessageBinding getBinding() {
|
||||
@@ -69,24 +67,25 @@ public class Saml2RedirectAuthenticationRequest extends AbstractSaml2Authenticat
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link Saml2RedirectAuthenticationRequest.Builder} from a {@link Saml2AuthenticationRequestContext} object.
|
||||
* By default the {@link Saml2RedirectAuthenticationRequest#getAuthenticationRequestUri()} will be set to the
|
||||
* {@link Saml2AuthenticationRequestContext#getDestination()} value.
|
||||
* @param context input providing {@code Destination}, {@code RelayState}, and {@code Issuer} objects.
|
||||
* Constructs a {@link Saml2RedirectAuthenticationRequest.Builder} from a
|
||||
* {@link Saml2AuthenticationRequestContext} object. By default the
|
||||
* {@link Saml2RedirectAuthenticationRequest#getAuthenticationRequestUri()} will be
|
||||
* set to the {@link Saml2AuthenticationRequestContext#getDestination()} value.
|
||||
* @param context input providing {@code Destination}, {@code RelayState}, and
|
||||
* {@code Issuer} objects.
|
||||
* @return a modifiable builder object
|
||||
*/
|
||||
public static Builder withAuthenticationRequestContext(Saml2AuthenticationRequestContext context) {
|
||||
return new Builder()
|
||||
.authenticationRequestUri(context.getDestination())
|
||||
.relayState(context.getRelayState())
|
||||
;
|
||||
return new Builder().authenticationRequestUri(context.getDestination()).relayState(context.getRelayState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for a {@link Saml2RedirectAuthenticationRequest} object.
|
||||
*/
|
||||
public static class Builder extends AbstractSaml2AuthenticationRequest.Builder<Builder> {
|
||||
|
||||
private String sigAlg;
|
||||
|
||||
private String signature;
|
||||
|
||||
private Builder() {
|
||||
@@ -118,16 +117,10 @@ public class Saml2RedirectAuthenticationRequest extends AbstractSaml2Authenticat
|
||||
* @return an immutable {@link Saml2RedirectAuthenticationRequest} object.
|
||||
*/
|
||||
public Saml2RedirectAuthenticationRequest build() {
|
||||
return new Saml2RedirectAuthenticationRequest(
|
||||
this.samlRequest,
|
||||
this.sigAlg,
|
||||
this.signature,
|
||||
this.relayState,
|
||||
this.authenticationRequestUri
|
||||
);
|
||||
return new Saml2RedirectAuthenticationRequest(this.samlRequest, this.sigAlg, this.signature,
|
||||
this.relayState, this.authenticationRequestUri);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -34,8 +34,7 @@ import static java.util.zip.Deflater.DEFLATED;
|
||||
*/
|
||||
final class Saml2Utils {
|
||||
|
||||
|
||||
private static Base64 BASE64 = new Base64(0, new byte[]{'\n'});
|
||||
private static Base64 BASE64 = new Base64(0, new byte[] { '\n' });
|
||||
|
||||
static String samlEncode(byte[] b) {
|
||||
return BASE64.encodeAsString(b);
|
||||
@@ -70,4 +69,5 @@ final class Saml2Utils {
|
||||
throw new Saml2Exception("Unable to inflate string", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-11
@@ -47,14 +47,15 @@ import static org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport.getB
|
||||
import static org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport.getMarshallerFactory;
|
||||
|
||||
/**
|
||||
* Resolves the SAML 2.0 Relying Party Metadata for a given {@link RelyingPartyRegistration}
|
||||
* using the OpenSAML API.
|
||||
* Resolves the SAML 2.0 Relying Party Metadata for a given
|
||||
* {@link RelyingPartyRegistration} using the OpenSAML API.
|
||||
*
|
||||
* @author Jakub Kubrynski
|
||||
* @author Josh Cummings
|
||||
* @since 5.4
|
||||
*/
|
||||
public final class OpenSamlMetadataResolver implements Saml2MetadataResolver {
|
||||
|
||||
static {
|
||||
OpenSamlInitializationService.initialize();
|
||||
}
|
||||
@@ -62,8 +63,8 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver {
|
||||
private final EntityDescriptorMarshaller entityDescriptorMarshaller;
|
||||
|
||||
public OpenSamlMetadataResolver() {
|
||||
this.entityDescriptorMarshaller = (EntityDescriptorMarshaller)
|
||||
getMarshallerFactory().getMarshaller(EntityDescriptor.DEFAULT_ELEMENT_NAME);
|
||||
this.entityDescriptorMarshaller = (EntityDescriptorMarshaller) getMarshallerFactory()
|
||||
.getMarshaller(EntityDescriptor.DEFAULT_ELEMENT_NAME);
|
||||
Assert.notNull(this.entityDescriptorMarshaller, "entityDescriptorMarshaller cannot be null");
|
||||
}
|
||||
|
||||
@@ -85,10 +86,10 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver {
|
||||
SPSSODescriptor spSsoDescriptor = build(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
|
||||
spSsoDescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
|
||||
spSsoDescriptor.setWantAssertionsSigned(true);
|
||||
spSsoDescriptor.getKeyDescriptors().addAll(buildKeys(
|
||||
registration.getSigningX509Credentials(), UsageType.SIGNING));
|
||||
spSsoDescriptor.getKeyDescriptors().addAll(buildKeys(
|
||||
registration.getDecryptionX509Credentials(), UsageType.ENCRYPTION));
|
||||
spSsoDescriptor.getKeyDescriptors()
|
||||
.addAll(buildKeys(registration.getSigningX509Credentials(), UsageType.SIGNING));
|
||||
spSsoDescriptor.getKeyDescriptors()
|
||||
.addAll(buildKeys(registration.getDecryptionX509Credentials(), UsageType.ENCRYPTION));
|
||||
spSsoDescriptor.getAssertionConsumerServices().add(buildAssertionConsumerService(registration));
|
||||
return spSsoDescriptor;
|
||||
}
|
||||
@@ -110,7 +111,8 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver {
|
||||
|
||||
try {
|
||||
x509Certificate.setValue(new String(Base64.getEncoder().encode(certificate.getEncoded())));
|
||||
} catch (CertificateEncodingException e) {
|
||||
}
|
||||
catch (CertificateEncodingException e) {
|
||||
throw new Saml2Exception("Cannot encode certificate " + certificate.toString());
|
||||
}
|
||||
|
||||
@@ -139,13 +141,14 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver {
|
||||
return (T) builder.buildObject(elementName);
|
||||
}
|
||||
|
||||
|
||||
private String serialize(EntityDescriptor entityDescriptor) {
|
||||
try {
|
||||
Element element = this.entityDescriptorMarshaller.marshall(entityDescriptor);
|
||||
return SerializeSupport.prettyPrintXML(element);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -19,18 +19,20 @@ package org.springframework.security.saml2.provider.service.metadata;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
|
||||
/**
|
||||
* Resolves the SAML 2.0 Relying Party Metadata for a given {@link RelyingPartyRegistration}
|
||||
* Resolves the SAML 2.0 Relying Party Metadata for a given
|
||||
* {@link RelyingPartyRegistration}
|
||||
*
|
||||
* @author Jakub Kubrynski
|
||||
* @author Josh Cummings
|
||||
* @since 5.4
|
||||
*/
|
||||
public interface Saml2MetadataResolver {
|
||||
|
||||
/**
|
||||
* Resolve the given relying party's metadata
|
||||
*
|
||||
* @param relyingPartyRegistration the relying party
|
||||
* @return the relying party's metadata
|
||||
*/
|
||||
String resolve(RelyingPartyRegistration relyingPartyRegistration);
|
||||
|
||||
}
|
||||
|
||||
+3
-4
@@ -46,14 +46,13 @@ public class InMemoryRelyingPartyRegistrationRepository
|
||||
}
|
||||
|
||||
private static Map<String, RelyingPartyRegistration> createMappingToIdentityProvider(
|
||||
Collection<RelyingPartyRegistration> rps
|
||||
) {
|
||||
Collection<RelyingPartyRegistration> rps) {
|
||||
LinkedHashMap<String, RelyingPartyRegistration> result = new LinkedHashMap<>();
|
||||
for (RelyingPartyRegistration rp : rps) {
|
||||
notNull(rp, "relying party collection cannot contain null values");
|
||||
String key = rp.getRegistrationId();
|
||||
notNull(rp, "relying party identifier cannot be null");
|
||||
Assert.isNull(result.get(key), () -> "relying party duplicate identifier '" + key+"' detected.");
|
||||
Assert.isNull(result.get(key), () -> "relying party duplicate identifier '" + key + "' detected.");
|
||||
result.put(key, rp);
|
||||
}
|
||||
return Collections.unmodifiableMap(result);
|
||||
@@ -61,7 +60,7 @@ public class InMemoryRelyingPartyRegistrationRepository
|
||||
|
||||
@Override
|
||||
public RelyingPartyRegistration findByRegistrationId(String id) {
|
||||
return this.byRegistrationId.get(id);
|
||||
return this.byRegistrationId.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+31
-22
@@ -54,12 +54,13 @@ import static org.springframework.security.saml2.core.Saml2X509Credential.verifi
|
||||
import static org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.withRegistrationId;
|
||||
|
||||
/**
|
||||
* An {@link HttpMessageConverter} that takes an {@code IDPSSODescriptor} in an HTTP response
|
||||
* and converts it into a {@link RelyingPartyRegistration.Builder}.
|
||||
* An {@link HttpMessageConverter} that takes an {@code IDPSSODescriptor} in an HTTP
|
||||
* response and converts it into a {@link RelyingPartyRegistration.Builder}.
|
||||
*
|
||||
* The primary use case for this is constructing a {@link RelyingPartyRegistration} for inclusion in a
|
||||
* {@link RelyingPartyRegistrationRepository}. To do so, you can include an instance of this converter in a
|
||||
* {@link org.springframework.web.client.RestOperations} like so:
|
||||
* The primary use case for this is constructing a {@link RelyingPartyRegistration} for
|
||||
* inclusion in a {@link RelyingPartyRegistrationRepository}. To do so, you can include an
|
||||
* instance of this converter in a {@link org.springframework.web.client.RestOperations}
|
||||
* like so:
|
||||
*
|
||||
* <pre>
|
||||
* RestOperations rest = new RestTemplate(Collections.singletonList(
|
||||
@@ -69,11 +70,12 @@ import static org.springframework.security.saml2.provider.service.registration.R
|
||||
* RelyingPartyRegistration registration = builder.registrationId("registration-id").build();
|
||||
* </pre>
|
||||
*
|
||||
* Note that this will only configure the asserting party (IDP) half of the {@link RelyingPartyRegistration},
|
||||
* meaning where and how to send AuthnRequests, how to verify Assertions, etc.
|
||||
* Note that this will only configure the asserting party (IDP) half of the
|
||||
* {@link RelyingPartyRegistration}, meaning where and how to send AuthnRequests, how to
|
||||
* verify Assertions, etc.
|
||||
*
|
||||
* To further configure the {@link RelyingPartyRegistration} with relying party (SP) information, you may
|
||||
* invoke the appropriate methods on the builder.
|
||||
* To further configure the {@link RelyingPartyRegistration} with relying party (SP)
|
||||
* information, you may invoke the appropriate methods on the builder.
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 5.4
|
||||
@@ -86,6 +88,7 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter
|
||||
}
|
||||
|
||||
private final EntityDescriptorUnmarshaller unmarshaller;
|
||||
|
||||
private final ParserPool parserPool;
|
||||
|
||||
/**
|
||||
@@ -126,8 +129,8 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public RelyingPartyRegistration.Builder read(Class<? extends RelyingPartyRegistration.Builder> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
public RelyingPartyRegistration.Builder read(Class<? extends RelyingPartyRegistration.Builder> clazz,
|
||||
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
|
||||
|
||||
EntityDescriptor descriptor = entityDescriptor(inputMessage.getBody());
|
||||
IDPSSODescriptor idpssoDescriptor = descriptor.getIDPSSODescriptor(SAML20P_NS);
|
||||
@@ -158,11 +161,11 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter
|
||||
}
|
||||
}
|
||||
if (verification.isEmpty()) {
|
||||
throw new Saml2Exception("Metadata response is missing verification certificates, necessary for verifying SAML assertions");
|
||||
throw new Saml2Exception(
|
||||
"Metadata response is missing verification certificates, necessary for verifying SAML assertions");
|
||||
}
|
||||
RelyingPartyRegistration.Builder builder = withRegistrationId(descriptor.getEntityID())
|
||||
.assertingPartyDetails(party -> party
|
||||
.entityId(descriptor.getEntityID())
|
||||
.assertingPartyDetails(party -> party.entityId(descriptor.getEntityID())
|
||||
.wantAuthnRequestsSigned(TRUE.equals(idpssoDescriptor.getWantAuthnRequestsSigned()))
|
||||
.verificationX509Credentials(c -> c.addAll(verification))
|
||||
.encryptionX509Credentials(c -> c.addAll(encryption)));
|
||||
@@ -170,23 +173,26 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter
|
||||
Saml2MessageBinding binding;
|
||||
if (singleSignOnService.getBinding().equals(Saml2MessageBinding.POST.getUrn())) {
|
||||
binding = Saml2MessageBinding.POST;
|
||||
} else if (singleSignOnService.getBinding().equals(Saml2MessageBinding.REDIRECT.getUrn())) {
|
||||
}
|
||||
else if (singleSignOnService.getBinding().equals(Saml2MessageBinding.REDIRECT.getUrn())) {
|
||||
binding = Saml2MessageBinding.REDIRECT;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
builder.assertingPartyDetails(party -> party
|
||||
.singleSignOnServiceLocation(singleSignOnService.getLocation())
|
||||
builder.assertingPartyDetails(party -> party.singleSignOnServiceLocation(singleSignOnService.getLocation())
|
||||
.singleSignOnServiceBinding(binding));
|
||||
return builder;
|
||||
}
|
||||
throw new Saml2Exception("Metadata response is missing a SingleSignOnService, necessary for sending AuthnRequests");
|
||||
throw new Saml2Exception(
|
||||
"Metadata response is missing a SingleSignOnService, necessary for sending AuthnRequests");
|
||||
}
|
||||
|
||||
private List<X509Certificate> certificates(KeyDescriptor keyDescriptor) {
|
||||
try {
|
||||
return KeyInfoSupport.getCertificates(keyDescriptor.getKeyInfo());
|
||||
} catch (CertificateException e) {
|
||||
}
|
||||
catch (CertificateException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
@@ -196,13 +202,16 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter
|
||||
Document document = this.parserPool.parse(inputStream);
|
||||
Element element = document.getDocumentElement();
|
||||
return (EntityDescriptor) this.unmarshaller.unmarshall(element);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(RelyingPartyRegistration.Builder builder, MediaType contentType, HttpOutputMessage outputMessage) throws HttpMessageNotWritableException {
|
||||
public void write(RelyingPartyRegistration.Builder builder, MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws HttpMessageNotWritableException {
|
||||
throw new HttpMessageNotWritableException("This converter cannot write a RelyingPartyRegistration.Builder");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+262
-220
@@ -28,14 +28,18 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.ProviderDetails;
|
||||
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Represents a configured relying party (aka Service Provider) and asserting party (aka Identity Provider) pair.
|
||||
* Represents a configured relying party (aka Service Provider) and asserting party (aka
|
||||
* Identity Provider) pair.
|
||||
*
|
||||
* <p>
|
||||
* Each RP/AP pair is uniquely identified using a {@code registrationId}, an arbitrary string.
|
||||
* Each RP/AP pair is uniquely identified using a {@code registrationId}, an arbitrary
|
||||
* string.
|
||||
*
|
||||
* <p>
|
||||
* A fully configured registration may look like:
|
||||
@@ -70,20 +74,23 @@ import org.springframework.util.Assert;
|
||||
public class RelyingPartyRegistration {
|
||||
|
||||
private final String registrationId;
|
||||
|
||||
private final String entityId;
|
||||
|
||||
private final String assertionConsumerServiceLocation;
|
||||
|
||||
private final Saml2MessageBinding assertionConsumerServiceBinding;
|
||||
|
||||
private final ProviderDetails providerDetails;
|
||||
|
||||
private final List<org.springframework.security.saml2.credentials.Saml2X509Credential> credentials;
|
||||
|
||||
private final Collection<Saml2X509Credential> decryptionX509Credentials;
|
||||
|
||||
private final Collection<Saml2X509Credential> signingX509Credentials;
|
||||
|
||||
private RelyingPartyRegistration(
|
||||
String registrationId,
|
||||
String entityId,
|
||||
String assertionConsumerServiceLocation,
|
||||
Saml2MessageBinding assertionConsumerServiceBinding,
|
||||
ProviderDetails providerDetails,
|
||||
private RelyingPartyRegistration(String registrationId, String entityId, String assertionConsumerServiceLocation,
|
||||
Saml2MessageBinding assertionConsumerServiceBinding, ProviderDetails providerDetails,
|
||||
Collection<org.springframework.security.saml2.credentials.Saml2X509Credential> credentials,
|
||||
Collection<Saml2X509Credential> decryptionX509Credentials,
|
||||
Collection<Saml2X509Credential> signingX509Credentials) {
|
||||
@@ -106,8 +113,7 @@ public class RelyingPartyRegistration {
|
||||
Assert.notNull(signingX509Credentials, "signingX509Credentials cannot be null");
|
||||
for (Saml2X509Credential c : signingX509Credentials) {
|
||||
Assert.notNull(c, "signingX509Credentials cannot contain null elements");
|
||||
Assert.isTrue(c.isSigningCredential(),
|
||||
"All signingX509Credentials must have a usage of SIGNING set");
|
||||
Assert.isTrue(c.isSigningCredential(), "All signingX509Credentials must have a usage of SIGNING set");
|
||||
}
|
||||
this.registrationId = registrationId;
|
||||
this.entityId = entityId;
|
||||
@@ -121,7 +127,6 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* Get the unique registration id for this RP/AP pair
|
||||
*
|
||||
* @return the unique registration id for this RP/AP pair
|
||||
*/
|
||||
public String getRegistrationId() {
|
||||
@@ -129,18 +134,17 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relying party's
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
* Get the relying party's <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to the value found in the relying party's
|
||||
* <EntityDescriptor EntityID="..."/>
|
||||
* Equivalent to the value found in the relying party's <EntityDescriptor
|
||||
* EntityID="..."/>
|
||||
*
|
||||
* <p>
|
||||
* This value may contain a number of placeholders, which need to be
|
||||
* resolved before use. They are {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
|
||||
*
|
||||
* This value may contain a number of placeholders, which need to be resolved before
|
||||
* use. They are {@code baseUrl}, {@code registrationId}, {@code baseScheme},
|
||||
* {@code baseHost}, and {@code basePort}.
|
||||
* @return the relying party's EntityID
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -149,14 +153,13 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the AssertionConsumerService Location.
|
||||
* Equivalent to the value found in <AssertionConsumerService Location="..."/>
|
||||
* in the relying party's <SPSSODescriptor>.
|
||||
*
|
||||
* This value may contain a number of placeholders, which need to be
|
||||
* resolved before use. They are {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
|
||||
* Get the AssertionConsumerService Location. Equivalent to the value found in
|
||||
* <AssertionConsumerService Location="..."/> in the relying party's
|
||||
* <SPSSODescriptor>.
|
||||
*
|
||||
* This value may contain a number of placeholders, which need to be resolved before
|
||||
* use. They are {@code baseUrl}, {@code registrationId}, {@code baseScheme},
|
||||
* {@code baseHost}, and {@code basePort}.
|
||||
* @return the AssertionConsumerService Location
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -165,10 +168,9 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the AssertionConsumerService Binding.
|
||||
* Equivalent to the value found in <AssertionConsumerService Binding="..."/>
|
||||
* in the relying party's <SPSSODescriptor>.
|
||||
*
|
||||
* Get the AssertionConsumerService Binding. Equivalent to the value found in
|
||||
* <AssertionConsumerService Binding="..."/> in the relying party's
|
||||
* <SPSSODescriptor>.
|
||||
* @return the AssertionConsumerService Binding
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -177,9 +179,10 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Collection} of decryption {@link Saml2X509Credential}s associated with this relying party
|
||||
*
|
||||
* @return the {@link Collection} of decryption {@link Saml2X509Credential}s associated with this relying party
|
||||
* Get the {@link Collection} of decryption {@link Saml2X509Credential}s associated
|
||||
* with this relying party
|
||||
* @return the {@link Collection} of decryption {@link Saml2X509Credential}s
|
||||
* associated with this relying party
|
||||
* @since 5.4
|
||||
*/
|
||||
public Collection<Saml2X509Credential> getDecryptionX509Credentials() {
|
||||
@@ -187,9 +190,10 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Collection} of signing {@link Saml2X509Credential}s associated with this relying party
|
||||
*
|
||||
* @return the {@link Collection} of signing {@link Saml2X509Credential}s associated with this relying party
|
||||
* Get the {@link Collection} of signing {@link Saml2X509Credential}s associated with
|
||||
* this relying party
|
||||
* @return the {@link Collection} of signing {@link Saml2X509Credential}s associated
|
||||
* with this relying party
|
||||
* @since 5.4
|
||||
*/
|
||||
public Collection<Saml2X509Credential> getSigningX509Credentials() {
|
||||
@@ -198,7 +202,6 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* Get the configuration details for the Asserting Party
|
||||
*
|
||||
* @return the {@link AssertingPartyDetails}
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -209,7 +212,8 @@ public class RelyingPartyRegistration {
|
||||
/**
|
||||
* Returns the entity ID of the IDP, the asserting party.
|
||||
* @return entity ID of the asserting party
|
||||
* @deprecated use {@link AssertingPartyDetails#getEntityId} from {@link #getAssertingPartyDetails}
|
||||
* @deprecated use {@link AssertingPartyDetails#getEntityId} from
|
||||
* {@link #getAssertingPartyDetails}
|
||||
*/
|
||||
@Deprecated
|
||||
public String getRemoteIdpEntityId() {
|
||||
@@ -218,8 +222,8 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* returns the URL template for which ACS URL authentication requests should contain
|
||||
* Possible variables are {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
|
||||
* Possible variables are {@code baseUrl}, {@code registrationId}, {@code baseScheme},
|
||||
* {@code baseHost}, and {@code basePort}.
|
||||
* @return string containing the ACS URL template, with or without variables present
|
||||
* @deprecated Use {@link #getAssertionConsumerServiceLocation} instead
|
||||
*/
|
||||
@@ -229,10 +233,11 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains the URL for which to send the SAML 2 Authentication Request to initiate
|
||||
* a single sign on flow.
|
||||
* Contains the URL for which to send the SAML 2 Authentication Request to initiate a
|
||||
* single sign on flow.
|
||||
* @return a IDP URL that accepts REDIRECT or POST binding for authentication requests
|
||||
* @deprecated use {@link AssertingPartyDetails#getSingleSignOnServiceLocation} from {@link #getAssertingPartyDetails}
|
||||
* @deprecated use {@link AssertingPartyDetails#getSingleSignOnServiceLocation} from
|
||||
* {@link #getAssertingPartyDetails}
|
||||
*/
|
||||
@Deprecated
|
||||
public String getIdpWebSsoUrl() {
|
||||
@@ -252,8 +257,8 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* The local relying party, or Service Provider, can generate it's entity ID based on
|
||||
* possible variables of {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}, for example
|
||||
* possible variables of {@code baseUrl}, {@code registrationId}, {@code baseScheme},
|
||||
* {@code baseHost}, and {@code basePort}, for example
|
||||
* {@code {baseUrl}/saml2/service-provider-metadata/{registrationId}}
|
||||
* @return a string containing the entity ID or entity ID template
|
||||
* @deprecated Use {@link #getEntityId} instead
|
||||
@@ -264,10 +269,11 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of configured credentials to be used in message exchanges between relying party, SP, and
|
||||
* asserting party, IDP.
|
||||
* Returns a list of configured credentials to be used in message exchanges between
|
||||
* relying party, SP, and asserting party, IDP.
|
||||
* @return a list of credentials
|
||||
* @deprecated Instead of retrieving all credentials, use the appropriate method for obtaining the correct type
|
||||
* @deprecated Instead of retrieving all credentials, use the appropriate method for
|
||||
* obtaining the correct type
|
||||
*/
|
||||
@Deprecated
|
||||
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getCredentials() {
|
||||
@@ -278,11 +284,13 @@ public class RelyingPartyRegistration {
|
||||
* @return a filtered list containing only credentials of type
|
||||
* {@link org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType#VERIFICATION}.
|
||||
* Returns an empty list of credentials are not found
|
||||
* @deprecated Use {@link #getAssertingPartyDetails().getSigningX509Credentials()} instead
|
||||
* @deprecated Use {@link #getAssertingPartyDetails().getSigningX509Credentials()}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getVerificationCredentials() {
|
||||
return filterCredentials(org.springframework.security.saml2.credentials.Saml2X509Credential::isSignatureVerficationCredential);
|
||||
return filterCredentials(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential::isSignatureVerficationCredential);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,18 +301,21 @@ public class RelyingPartyRegistration {
|
||||
*/
|
||||
@Deprecated
|
||||
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getSigningCredentials() {
|
||||
return filterCredentials(org.springframework.security.saml2.credentials.Saml2X509Credential::isSigningCredential);
|
||||
return filterCredentials(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential::isSigningCredential);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a filtered list containing only credentials of type
|
||||
* {@link org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType#ENCRYPTION}.
|
||||
* Returns an empty list of credentials are not found
|
||||
* @deprecated Use {@link AssertingPartyDetails#getEncryptionX509Credentials()} instead
|
||||
* @deprecated Use {@link AssertingPartyDetails#getEncryptionX509Credentials()}
|
||||
* instead
|
||||
*/
|
||||
@Deprecated
|
||||
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getEncryptionCredentials() {
|
||||
return filterCredentials(org.springframework.security.saml2.credentials.Saml2X509Credential::isEncryptionCredential);
|
||||
return filterCredentials(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential::isEncryptionCredential);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,7 +326,8 @@ public class RelyingPartyRegistration {
|
||||
*/
|
||||
@Deprecated
|
||||
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getDecryptionCredentials() {
|
||||
return filterCredentials(org.springframework.security.saml2.credentials.Saml2X509Credential::isDecryptionCredential);
|
||||
return filterCredentials(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential::isDecryptionCredential);
|
||||
}
|
||||
|
||||
private List<org.springframework.security.saml2.credentials.Saml2X509Credential> filterCredentials(
|
||||
@@ -331,7 +343,8 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code RelyingPartyRegistration} {@link Builder} with a known {@code registrationId}
|
||||
* Creates a {@code RelyingPartyRegistration} {@link Builder} with a known
|
||||
* {@code registrationId}
|
||||
* @param registrationId a string identifier for the {@code RelyingPartyRegistration}
|
||||
* @return {@code Builder} to create a {@code RelyingPartyRegistration} object
|
||||
*/
|
||||
@@ -341,48 +354,53 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code RelyingPartyRegistration} {@link Builder} based on an existing object
|
||||
* Creates a {@code RelyingPartyRegistration} {@link Builder} based on an existing
|
||||
* object
|
||||
* @param registration the {@code RelyingPartyRegistration}
|
||||
* @return {@code Builder} to create a {@code RelyingPartyRegistration} object
|
||||
*/
|
||||
public static Builder withRelyingPartyRegistration(RelyingPartyRegistration registration) {
|
||||
Assert.notNull(registration, "registration cannot be null");
|
||||
return withRegistrationId(registration.getRegistrationId())
|
||||
.entityId(registration.getEntityId())
|
||||
return withRegistrationId(registration.getRegistrationId()).entityId(registration.getEntityId())
|
||||
.signingX509Credentials(c -> c.addAll(registration.getSigningX509Credentials()))
|
||||
.decryptionX509Credentials(c -> c.addAll(registration.getDecryptionX509Credentials()))
|
||||
.assertionConsumerServiceLocation(registration.getAssertionConsumerServiceLocation())
|
||||
.assertionConsumerServiceBinding(registration.getAssertionConsumerServiceBinding())
|
||||
.assertingPartyDetails(assertingParty -> assertingParty
|
||||
.entityId(registration.getAssertingPartyDetails().getEntityId())
|
||||
.wantAuthnRequestsSigned(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned())
|
||||
.verificationX509Credentials(c -> c.addAll(registration.getAssertingPartyDetails().getVerificationX509Credentials()))
|
||||
.encryptionX509Credentials(c -> c.addAll(registration.getAssertingPartyDetails().getEncryptionX509Credentials()))
|
||||
.singleSignOnServiceLocation(registration.getAssertingPartyDetails().getSingleSignOnServiceLocation())
|
||||
.singleSignOnServiceBinding(registration.getAssertingPartyDetails().getSingleSignOnServiceBinding())
|
||||
);
|
||||
.entityId(registration.getAssertingPartyDetails().getEntityId())
|
||||
.wantAuthnRequestsSigned(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned())
|
||||
.verificationX509Credentials(
|
||||
c -> c.addAll(registration.getAssertingPartyDetails().getVerificationX509Credentials()))
|
||||
.encryptionX509Credentials(
|
||||
c -> c.addAll(registration.getAssertingPartyDetails().getEncryptionX509Credentials()))
|
||||
.singleSignOnServiceLocation(
|
||||
registration.getAssertingPartyDetails().getSingleSignOnServiceLocation())
|
||||
.singleSignOnServiceBinding(
|
||||
registration.getAssertingPartyDetails().getSingleSignOnServiceBinding()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The configuration metadata of the Asserting party
|
||||
*
|
||||
* @since 5.4
|
||||
*/
|
||||
public final static class AssertingPartyDetails {
|
||||
|
||||
private final String entityId;
|
||||
|
||||
private final boolean wantAuthnRequestsSigned;
|
||||
|
||||
private final Collection<Saml2X509Credential> verificationX509Credentials;
|
||||
|
||||
private final Collection<Saml2X509Credential> encryptionX509Credentials;
|
||||
|
||||
private final String singleSignOnServiceLocation;
|
||||
|
||||
private final Saml2MessageBinding singleSignOnServiceBinding;
|
||||
|
||||
private AssertingPartyDetails(
|
||||
String entityId,
|
||||
boolean wantAuthnRequestsSigned,
|
||||
private AssertingPartyDetails(String entityId, boolean wantAuthnRequestsSigned,
|
||||
Collection<Saml2X509Credential> verificationX509Credentials,
|
||||
Collection<Saml2X509Credential> encryptionX509Credentials,
|
||||
String singleSignOnServiceLocation,
|
||||
Collection<Saml2X509Credential> encryptionX509Credentials, String singleSignOnServiceLocation,
|
||||
Saml2MessageBinding singleSignOnServiceBinding) {
|
||||
|
||||
Assert.hasText(entityId, "entityId cannot be null or empty");
|
||||
@@ -409,18 +427,17 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the asserting party's
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
* Get the asserting party's <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to the value found in the asserting party's
|
||||
* <EntityDescriptor EntityID="..."/>
|
||||
* Equivalent to the value found in the asserting party's <EntityDescriptor
|
||||
* EntityID="..."/>
|
||||
*
|
||||
* <p>
|
||||
* This value may contain a number of placeholders, which need to be
|
||||
* resolved before use. They are {@code baseUrl}, {@code registrationId},
|
||||
* This value may contain a number of placeholders, which need to be resolved
|
||||
* before use. They are {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
|
||||
*
|
||||
* @return the asserting party's EntityID
|
||||
*/
|
||||
public String getEntityId() {
|
||||
@@ -428,9 +445,8 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WantAuthnRequestsSigned setting, indicating the asserting party's preference that
|
||||
* relying parties should sign the AuthnRequest before sending.
|
||||
*
|
||||
* Get the WantAuthnRequestsSigned setting, indicating the asserting party's
|
||||
* preference that relying parties should sign the AuthnRequest before sending.
|
||||
* @return the WantAuthnRequestsSigned value
|
||||
*/
|
||||
public boolean getWantAuthnRequestsSigned() {
|
||||
@@ -438,9 +454,10 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all verification {@link Saml2X509Credential}s associated with this asserting party
|
||||
*
|
||||
* @return all verification {@link Saml2X509Credential}s associated with this asserting party
|
||||
* Get all verification {@link Saml2X509Credential}s associated with this
|
||||
* asserting party
|
||||
* @return all verification {@link Saml2X509Credential}s associated with this
|
||||
* asserting party
|
||||
* @since 5.4
|
||||
*/
|
||||
public Collection<Saml2X509Credential> getVerificationX509Credentials() {
|
||||
@@ -448,9 +465,10 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all encryption {@link Saml2X509Credential}s associated with this asserting party
|
||||
*
|
||||
* @return all encryption {@link Saml2X509Credential}s associated with this asserting party
|
||||
* Get all encryption {@link Saml2X509Credential}s associated with this asserting
|
||||
* party
|
||||
* @return all encryption {@link Saml2X509Credential}s associated with this
|
||||
* asserting party
|
||||
* @since 5.4
|
||||
*/
|
||||
public Collection<Saml2X509Credential> getEncryptionX509Credentials() {
|
||||
@@ -458,14 +476,13 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
|
||||
* Get the <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
|
||||
* Location.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to the value found in <SingleSignOnService Location="..."/>
|
||||
* in the asserting party's <IDPSSODescriptor>.
|
||||
*
|
||||
* Equivalent to the value found in <SingleSignOnService Location="..."/> in
|
||||
* the asserting party's <IDPSSODescriptor>.
|
||||
* @return the SingleSignOnService Location
|
||||
*/
|
||||
public String getSingleSignOnServiceLocation() {
|
||||
@@ -473,14 +490,13 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
|
||||
* Get the <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
|
||||
* Binding.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to the value found in <SingleSignOnService Binding="..."/>
|
||||
* in the asserting party's <IDPSSODescriptor>.
|
||||
*
|
||||
* Equivalent to the value found in <SingleSignOnService Binding="..."/> in
|
||||
* the asserting party's <IDPSSODescriptor>.
|
||||
* @return the SingleSignOnService Location
|
||||
*/
|
||||
public Saml2MessageBinding getSingleSignOnServiceBinding() {
|
||||
@@ -488,19 +504,24 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
public final static class Builder {
|
||||
|
||||
private String entityId;
|
||||
|
||||
private boolean wantAuthnRequestsSigned = true;
|
||||
|
||||
private Collection<Saml2X509Credential> verificationX509Credentials = new HashSet<>();
|
||||
|
||||
private Collection<Saml2X509Credential> encryptionX509Credentials = new HashSet<>();
|
||||
|
||||
private String singleSignOnServiceLocation;
|
||||
|
||||
private Saml2MessageBinding singleSignOnServiceBinding = Saml2MessageBinding.REDIRECT;
|
||||
|
||||
/**
|
||||
* Set the asserting party's
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
* Equivalent to the value found in the asserting party's
|
||||
* <EntityDescriptor EntityID="..."/>
|
||||
*
|
||||
* Set the asserting party's <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
* Equivalent to the value found in the asserting party's <EntityDescriptor
|
||||
* EntityID="..."/>
|
||||
* @param entityId the asserting party's EntityID
|
||||
* @return the {@link ProviderDetails.Builder} for further configuration
|
||||
*/
|
||||
@@ -510,9 +531,9 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the WantAuthnRequestsSigned setting, indicating the asserting party's preference that
|
||||
* relying parties should sign the AuthnRequest before sending.
|
||||
*
|
||||
* Set the WantAuthnRequestsSigned setting, indicating the asserting party's
|
||||
* preference that relying parties should sign the AuthnRequest before
|
||||
* sending.
|
||||
* @param wantAuthnRequestsSigned the WantAuthnRequestsSigned setting
|
||||
* @return the {@link ProviderDetails.Builder} for further configuration
|
||||
*/
|
||||
@@ -523,9 +544,10 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* Apply this {@link Consumer} to the list of {@link Saml2X509Credential}s
|
||||
*
|
||||
* @param credentialsConsumer a {@link Consumer} of the {@link List} of {@link Saml2X509Credential}s
|
||||
* @return the {@link RelyingPartyRegistration.Builder} for further configuration
|
||||
* @param credentialsConsumer a {@link Consumer} of the {@link List} of
|
||||
* {@link Saml2X509Credential}s
|
||||
* @return the {@link RelyingPartyRegistration.Builder} for further
|
||||
* configuration
|
||||
* @since 5.4
|
||||
*/
|
||||
public Builder verificationX509Credentials(Consumer<Collection<Saml2X509Credential>> credentialsConsumer) {
|
||||
@@ -535,9 +557,10 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* Apply this {@link Consumer} to the list of {@link Saml2X509Credential}s
|
||||
*
|
||||
* @param credentialsConsumer a {@link Consumer} of the {@link List} of {@link Saml2X509Credential}s
|
||||
* @return the {@link RelyingPartyRegistration.Builder} for further configuration
|
||||
* @param credentialsConsumer a {@link Consumer} of the {@link List} of
|
||||
* {@link Saml2X509Credential}s
|
||||
* @return the {@link RelyingPartyRegistration.Builder} for further
|
||||
* configuration
|
||||
* @since 5.4
|
||||
*/
|
||||
public Builder encryptionX509Credentials(Consumer<Collection<Saml2X509Credential>> credentialsConsumer) {
|
||||
@@ -546,14 +569,13 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
|
||||
* Set the <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
|
||||
* Location.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to the value found in <SingleSignOnService Location="..."/>
|
||||
* in the asserting party's <IDPSSODescriptor>.
|
||||
*
|
||||
* Equivalent to the value found in <SingleSignOnService
|
||||
* Location="..."/> in the asserting party's <IDPSSODescriptor>.
|
||||
* @param singleSignOnServiceLocation the SingleSignOnService Location
|
||||
* @return the {@link ProviderDetails.Builder} for further configuration
|
||||
*/
|
||||
@@ -563,14 +585,13 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
|
||||
* Set the <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/MetadataForIdP#MetadataForIdP-SingleSign-OnServices">SingleSignOnService</a>
|
||||
* Binding.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to the value found in <SingleSignOnService Binding="..."/>
|
||||
* in the asserting party's <IDPSSODescriptor>.
|
||||
*
|
||||
* @param singleSignOnServiceBinding the SingleSignOnService Binding
|
||||
* @return the {@link ProviderDetails.Builder} for further configuration
|
||||
*/
|
||||
@@ -580,29 +601,29 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an immutable ProviderDetails object representing the configuration for an Identity Provider, IDP
|
||||
* Creates an immutable ProviderDetails object representing the configuration
|
||||
* for an Identity Provider, IDP
|
||||
* @return immutable ProviderDetails object
|
||||
*/
|
||||
public AssertingPartyDetails build() {
|
||||
return new AssertingPartyDetails(
|
||||
this.entityId,
|
||||
this.wantAuthnRequestsSigned,
|
||||
this.verificationX509Credentials,
|
||||
this.encryptionX509Credentials,
|
||||
this.singleSignOnServiceLocation,
|
||||
this.singleSignOnServiceBinding
|
||||
);
|
||||
return new AssertingPartyDetails(this.entityId, this.wantAuthnRequestsSigned,
|
||||
this.verificationX509Credentials, this.encryptionX509Credentials,
|
||||
this.singleSignOnServiceLocation, this.singleSignOnServiceBinding);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for IDP SSO endpoint configuration
|
||||
*
|
||||
* @since 5.3
|
||||
* @deprecated Use {@link AssertingPartyDetails} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public final static class ProviderDetails {
|
||||
|
||||
private final AssertingPartyDetails assertingPartyDetails;
|
||||
|
||||
private ProviderDetails(AssertingPartyDetails assertingPartyDetails) {
|
||||
@@ -619,17 +640,18 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains the URL for which to send the SAML 2 Authentication Request to initiate
|
||||
* a single sign on flow.
|
||||
* @return a IDP URL that accepts REDIRECT or POST binding for authentication requests
|
||||
* Contains the URL for which to send the SAML 2 Authentication Request to
|
||||
* initiate a single sign on flow.
|
||||
* @return a IDP URL that accepts REDIRECT or POST binding for authentication
|
||||
* requests
|
||||
*/
|
||||
public String getWebSsoUrl() {
|
||||
return this.assertingPartyDetails.getSingleSignOnServiceLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if AuthNRequests from this relying party to the IDP should be signed
|
||||
* {@code false} if no signature is required.
|
||||
* @return {@code true} if AuthNRequests from this relying party to the IDP should
|
||||
* be signed {@code false} if no signature is required.
|
||||
*/
|
||||
public boolean isSignAuthNRequest() {
|
||||
return this.assertingPartyDetails.getWantAuthnRequestsSigned();
|
||||
@@ -644,20 +666,20 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* Builder for IDP SSO endpoint configuration
|
||||
*
|
||||
* @since 5.3
|
||||
* @deprecated Use {@link AssertingPartyDetails.Builder} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public final static class Builder {
|
||||
private final AssertingPartyDetails.Builder assertingPartyDetailsBuilder =
|
||||
new AssertingPartyDetails.Builder();
|
||||
|
||||
private final AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
|
||||
|
||||
/**
|
||||
* Set the asserting party's
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
* Equivalent to the value found in the asserting party's
|
||||
* <EntityDescriptor EntityID="..."/>
|
||||
*
|
||||
* Set the asserting party's <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
* Equivalent to the value found in the asserting party's <EntityDescriptor
|
||||
* EntityID="..."/>
|
||||
* @param entityId the asserting party's EntityID
|
||||
* @return the {@link Builder} for further configuration
|
||||
* @since 5.4
|
||||
@@ -668,9 +690,10 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code SSO URL} for the remote asserting party, the Identity Provider.
|
||||
*
|
||||
* @param url - a URL that accepts authentication requests via REDIRECT or POST bindings
|
||||
* Sets the {@code SSO URL} for the remote asserting party, the Identity
|
||||
* Provider.
|
||||
* @param url - a URL that accepts authentication requests via REDIRECT or
|
||||
* POST bindings
|
||||
* @return this object
|
||||
*/
|
||||
public Builder webSsoUrl(String url) {
|
||||
@@ -680,7 +703,6 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* Set to true if the AuthNRequest message should be signed
|
||||
*
|
||||
* @param signAuthNRequest true if the message should be signed
|
||||
* @return this object
|
||||
*/
|
||||
@@ -689,11 +711,10 @@ public class RelyingPartyRegistration {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the message binding to be used when sending an AuthNRequest message
|
||||
*
|
||||
* @param binding either {@link Saml2MessageBinding#POST} or {@link Saml2MessageBinding#REDIRECT}
|
||||
* @param binding either {@link Saml2MessageBinding#POST} or
|
||||
* {@link Saml2MessageBinding#REDIRECT}
|
||||
* @return this object
|
||||
*/
|
||||
public Builder binding(Saml2MessageBinding binding) {
|
||||
@@ -702,30 +723,41 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an immutable ProviderDetails object representing the configuration for an Identity Provider, IDP
|
||||
* Creates an immutable ProviderDetails object representing the configuration
|
||||
* for an Identity Provider, IDP
|
||||
* @return immutable ProviderDetails object
|
||||
*/
|
||||
public ProviderDetails build() {
|
||||
return new ProviderDetails(this.assertingPartyDetailsBuilder.build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final static class Builder {
|
||||
|
||||
private String registrationId;
|
||||
|
||||
private String entityId = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
|
||||
|
||||
private Collection<Saml2X509Credential> signingX509Credentials = new HashSet<>();
|
||||
|
||||
private Collection<Saml2X509Credential> decryptionX509Credentials = new HashSet<>();
|
||||
private String assertionConsumerServiceLocation = "{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
|
||||
|
||||
private String assertionConsumerServiceLocation = "{baseUrl}"
|
||||
+ Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
|
||||
|
||||
private Saml2MessageBinding assertionConsumerServiceBinding = Saml2MessageBinding.POST;
|
||||
|
||||
private ProviderDetails.Builder providerDetails = new ProviderDetails.Builder();
|
||||
|
||||
private Collection<org.springframework.security.saml2.credentials.Saml2X509Credential> credentials = new HashSet<>();
|
||||
|
||||
private Builder(String registrationId) {
|
||||
this.registrationId = registrationId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the {@code registrationId} template. Often be used in URL paths
|
||||
* @param id registrationId for this object, should be unique
|
||||
@@ -737,15 +769,14 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relying party's
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
* Equivalent to the value found in the relying party's
|
||||
* <EntityDescriptor EntityID="..."/>
|
||||
*
|
||||
* This value may contain a number of placeholders.
|
||||
* They are {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
|
||||
* Set the relying party's <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/EntityNaming">EntityID</a>.
|
||||
* Equivalent to the value found in the relying party's <EntityDescriptor
|
||||
* EntityID="..."/>
|
||||
*
|
||||
* This value may contain a number of placeholders. They are {@code baseUrl},
|
||||
* {@code registrationId}, {@code baseScheme}, {@code baseHost}, and
|
||||
* {@code basePort}.
|
||||
* @return the {@link Builder} for further configuration
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -755,10 +786,11 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply this {@link Consumer} to the {@link Collection} of {@link Saml2X509Credential}s
|
||||
* for the purposes of modifying the {@link Collection}
|
||||
*
|
||||
* @param credentialsConsumer - the {@link Consumer} for modifying the {@link Collection}
|
||||
* Apply this {@link Consumer} to the {@link Collection} of
|
||||
* {@link Saml2X509Credential}s for the purposes of modifying the
|
||||
* {@link Collection}
|
||||
* @param credentialsConsumer - the {@link Consumer} for modifying the
|
||||
* {@link Collection}
|
||||
* @return the {@link Builder} for further configuration
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -768,10 +800,11 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply this {@link Consumer} to the {@link Collection} of {@link Saml2X509Credential}s
|
||||
* for the purposes of modifying the {@link Collection}
|
||||
*
|
||||
* @param credentialsConsumer - the {@link Consumer} for modifying the {@link Collection}
|
||||
* Apply this {@link Consumer} to the {@link Collection} of
|
||||
* {@link Saml2X509Credential}s for the purposes of modifying the
|
||||
* {@link Collection}
|
||||
* @param credentialsConsumer - the {@link Consumer} for modifying the
|
||||
* {@link Collection}
|
||||
* @return the {@link Builder} for further configuration
|
||||
* @since 5.4
|
||||
*/
|
||||
@@ -781,18 +814,18 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">AssertionConsumerService</a>
|
||||
* Set the <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">AssertionConsumerService</a>
|
||||
* Location.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to the value found in <AssertionConsumerService Location="..."/>
|
||||
* in the relying party's <SPSSODescriptor>
|
||||
* Equivalent to the value found in <AssertionConsumerService
|
||||
* Location="..."/> in the relying party's <SPSSODescriptor>
|
||||
*
|
||||
* <p>
|
||||
* This value may contain a number of placeholders.
|
||||
* They are {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
|
||||
*
|
||||
* This value may contain a number of placeholders. They are {@code baseUrl},
|
||||
* {@code registrationId}, {@code baseScheme}, {@code baseHost}, and
|
||||
* {@code basePort}.
|
||||
* @param assertionConsumerServiceLocation
|
||||
* @return the {@link Builder} for further configuration
|
||||
* @since 5.4
|
||||
@@ -803,13 +836,13 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">AssertionConsumerService</a>
|
||||
* Set the <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">AssertionConsumerService</a>
|
||||
* Binding.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to the value found in <AssertionConsumerService Binding="..."/>
|
||||
* in the relying party's <SPSSODescriptor>
|
||||
*
|
||||
* Equivalent to the value found in <AssertionConsumerService
|
||||
* Binding="..."/> in the relying party's <SPSSODescriptor>
|
||||
* @param assertionConsumerServiceBinding
|
||||
* @return the {@link Builder} for further configuration
|
||||
* @since 5.4
|
||||
@@ -821,7 +854,6 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* Apply this {@link Consumer} to further configure the Asserting Party details
|
||||
*
|
||||
* @param assertingPartyDetails The {@link Consumer} to apply
|
||||
* @return the {@link Builder} for further configuration
|
||||
* @since 5.4
|
||||
@@ -832,10 +864,8 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the collection of {@link Saml2X509Credential} objects
|
||||
* used in communication between IDP and SP
|
||||
* For example:
|
||||
* <code>
|
||||
* Modifies the collection of {@link Saml2X509Credential} objects used in
|
||||
* communication between IDP and SP For example: <code>
|
||||
* Saml2X509Credential credential = ...;
|
||||
* return RelyingPartyRegistration.withRegistrationId("id")
|
||||
* .credentials(c -> c.add(credential))
|
||||
@@ -844,22 +874,27 @@ public class RelyingPartyRegistration {
|
||||
* </code>
|
||||
* @param credentials - a consumer that can modify the collection of credentials
|
||||
* @return this object
|
||||
* @deprecated Use {@link #signingX509Credentials} or {@link #decryptionX509Credentials} instead
|
||||
* for relying party keys or {@link AssertingPartyDetails.Builder#verificationX509Credentials} or
|
||||
* {@link AssertingPartyDetails.Builder#encryptionX509Credentials} for asserting party keys
|
||||
* @deprecated Use {@link #signingX509Credentials} or
|
||||
* {@link #decryptionX509Credentials} instead for relying party keys or
|
||||
* {@link AssertingPartyDetails.Builder#verificationX509Credentials} or
|
||||
* {@link AssertingPartyDetails.Builder#encryptionX509Credentials} for asserting
|
||||
* party keys
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder credentials(Consumer<Collection<org.springframework.security.saml2.credentials.Saml2X509Credential>> credentials) {
|
||||
public Builder credentials(
|
||||
Consumer<Collection<org.springframework.security.saml2.credentials.Saml2X509Credential>> credentials) {
|
||||
credentials.accept(this.credentials);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <a href="https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">Assertion Consumer
|
||||
* Service</a> URL template. It can contain variables {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}.
|
||||
* @param assertionConsumerServiceUrlTemplate the Assertion Consumer Service URL template (i.e.
|
||||
* "{baseUrl}/login/saml2/sso/{registrationId}".
|
||||
* <a href=
|
||||
* "https://wiki.shibboleth.net/confluence/display/CONCEPT/AssertionConsumerService">Assertion
|
||||
* Consumer Service</a> URL template. It can contain variables {@code baseUrl},
|
||||
* {@code registrationId}, {@code baseScheme}, {@code baseHost}, and
|
||||
* {@code basePort}.
|
||||
* @param assertionConsumerServiceUrlTemplate the Assertion Consumer Service URL
|
||||
* template (i.e. "{baseUrl}/login/saml2/sso/{registrationId}".
|
||||
* @return this object
|
||||
* @deprecated Use {@link #assertionConsumerServiceLocation} instead.
|
||||
*/
|
||||
@@ -870,10 +905,12 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code entityId} for the remote asserting party, the Identity Provider.
|
||||
* Sets the {@code entityId} for the remote asserting party, the Identity
|
||||
* Provider.
|
||||
* @param entityId the IDP entityId
|
||||
* @return this object
|
||||
* @deprecated use {@link #assertingPartyDetails(Consumer< AssertingPartyDetails.Builder >)}
|
||||
* @deprecated use {@link #assertingPartyDetails(Consumer<
|
||||
* AssertingPartyDetails.Builder >)}
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder remoteIdpEntityId(String entityId) {
|
||||
@@ -883,9 +920,11 @@ public class RelyingPartyRegistration {
|
||||
|
||||
/**
|
||||
* Sets the {@code SSO URL} for the remote asserting party, the Identity Provider.
|
||||
* @param url - a URL that accepts authentication requests via REDIRECT or POST bindings
|
||||
* @param url - a URL that accepts authentication requests via REDIRECT or POST
|
||||
* bindings
|
||||
* @return this object
|
||||
* @deprecated use {@link #assertingPartyDetails(Consumer< AssertingPartyDetails.Builder >)}
|
||||
* @deprecated use {@link #assertingPartyDetails(Consumer<
|
||||
* AssertingPartyDetails.Builder >)}
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder idpWebSsoUrl(String url) {
|
||||
@@ -894,9 +933,10 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the local relying party, or Service Provider, entity Id template.
|
||||
* can generate it's entity ID based on possible variables of {@code baseUrl}, {@code registrationId},
|
||||
* {@code baseScheme}, {@code baseHost}, and {@code basePort}, for example
|
||||
* Sets the local relying party, or Service Provider, entity Id template. can
|
||||
* generate it's entity ID based on possible variables of {@code baseUrl},
|
||||
* {@code registrationId}, {@code baseScheme}, {@code baseHost}, and
|
||||
* {@code basePort}, for example
|
||||
* {@code {baseUrl}/saml2/service-provider-metadata/{registrationId}}
|
||||
* @return a string containing the entity ID or entity ID template
|
||||
* @deprecated Use {@link #entityId} instead
|
||||
@@ -920,7 +960,8 @@ public class RelyingPartyRegistration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a RelyingPartyRegistration object based on the builder configurations
|
||||
* Constructs a RelyingPartyRegistration object based on the builder
|
||||
* configurations
|
||||
* @return a RelyingPartyRegistration instance
|
||||
*/
|
||||
public RelyingPartyRegistration build() {
|
||||
@@ -933,12 +974,10 @@ public class RelyingPartyRegistration {
|
||||
decryptionX509Credentials(c -> c.add(mapped));
|
||||
}
|
||||
if (credential.isSignatureVerficationCredential()) {
|
||||
this.providerDetails.assertingPartyDetailsBuilder
|
||||
.verificationX509Credentials(c -> c.add(mapped));
|
||||
this.providerDetails.assertingPartyDetailsBuilder.verificationX509Credentials(c -> c.add(mapped));
|
||||
}
|
||||
if (credential.isEncryptionCredential()) {
|
||||
this.providerDetails.assertingPartyDetailsBuilder
|
||||
.encryptionX509Credentials(c -> c.add(mapped));
|
||||
this.providerDetails.assertingPartyDetailsBuilder.encryptionX509Credentials(c -> c.add(mapped));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -955,20 +994,16 @@ public class RelyingPartyRegistration {
|
||||
this.credentials.add(toDeprecated(credential));
|
||||
}
|
||||
|
||||
return new RelyingPartyRegistration(
|
||||
this.registrationId,
|
||||
this.entityId,
|
||||
this.assertionConsumerServiceLocation,
|
||||
this.assertionConsumerServiceBinding,
|
||||
this.providerDetails.build(),
|
||||
this.credentials,
|
||||
this.decryptionX509Credentials,
|
||||
this.signingX509Credentials
|
||||
);
|
||||
return new RelyingPartyRegistration(this.registrationId, this.entityId,
|
||||
this.assertionConsumerServiceLocation, this.assertionConsumerServiceBinding,
|
||||
this.providerDetails.build(), this.credentials, this.decryptionX509Credentials,
|
||||
this.signingX509Credentials);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Saml2X509Credential fromDeprecated(org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
private static Saml2X509Credential fromDeprecated(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
PrivateKey privateKey = credential.getPrivateKey();
|
||||
X509Certificate certificate = credential.getCertificate();
|
||||
Set<Saml2X509Credential.Saml2X509CredentialType> credentialTypes = new HashSet<>();
|
||||
@@ -987,22 +1022,29 @@ public class RelyingPartyRegistration {
|
||||
return new Saml2X509Credential(privateKey, certificate, credentialTypes);
|
||||
}
|
||||
|
||||
private static org.springframework.security.saml2.credentials.Saml2X509Credential toDeprecated(Saml2X509Credential credential) {
|
||||
private static org.springframework.security.saml2.credentials.Saml2X509Credential toDeprecated(
|
||||
Saml2X509Credential credential) {
|
||||
PrivateKey privateKey = credential.getPrivateKey();
|
||||
X509Certificate certificate = credential.getCertificate();
|
||||
Set<org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType> credentialTypes = new HashSet<>();
|
||||
if (credential.isSigningCredential()) {
|
||||
credentialTypes.add(org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.SIGNING);
|
||||
credentialTypes.add(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.SIGNING);
|
||||
}
|
||||
if (credential.isVerificationCredential()) {
|
||||
credentialTypes.add(org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
|
||||
credentialTypes.add(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
|
||||
}
|
||||
if (credential.isEncryptionCredential()) {
|
||||
credentialTypes.add(org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
|
||||
credentialTypes.add(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
|
||||
}
|
||||
if (credential.isDecryptionCredential()) {
|
||||
credentialTypes.add(org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
|
||||
credentialTypes.add(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
|
||||
}
|
||||
return new org.springframework.security.saml2.credentials.Saml2X509Credential(privateKey, certificate, credentialTypes);
|
||||
return new org.springframework.security.saml2.credentials.Saml2X509Credential(privateKey, certificate,
|
||||
credentialTypes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -25,9 +25,8 @@ package org.springframework.security.saml2.provider.service.registration;
|
||||
public interface RelyingPartyRegistrationRepository {
|
||||
|
||||
/**
|
||||
* Returns the relying party registration identified by the provided {@code registrationId},
|
||||
* or {@code null} if not found.
|
||||
*
|
||||
* Returns the relying party registration identified by the provided
|
||||
* {@code registrationId}, or {@code null} if not found.
|
||||
* @param registrationId the registration identifier
|
||||
* @return the {@link RelyingPartyRegistration} if found, otherwise {@code null}
|
||||
*/
|
||||
|
||||
+12
-9
@@ -30,12 +30,13 @@ import org.springframework.web.client.RestTemplate;
|
||||
* @since 5.4
|
||||
*/
|
||||
public final class RelyingPartyRegistrations {
|
||||
private static final RestOperations rest = new RestTemplate
|
||||
(Arrays.asList(new OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter()));
|
||||
|
||||
private static final RestOperations rest = new RestTemplate(
|
||||
Arrays.asList(new OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter()));
|
||||
|
||||
/**
|
||||
* Return a {@link RelyingPartyRegistration.Builder} based off of the given
|
||||
* SAML 2.0 Asserting Party (IDP) metadata.
|
||||
* Return a {@link RelyingPartyRegistration.Builder} based off of the given SAML 2.0
|
||||
* Asserting Party (IDP) metadata.
|
||||
*
|
||||
* Note that by default the registrationId is set to be the given metadata location,
|
||||
* but this will most often not be sufficient. To complete the configuration, most
|
||||
@@ -48,21 +49,23 @@ public final class RelyingPartyRegistrations {
|
||||
* .build();
|
||||
* </pre>
|
||||
*
|
||||
* Also note that an {@code IDPSSODescriptor} typically only contains information about
|
||||
* the asserting party. Thus, you will need to remember to still populate anything about the
|
||||
* relying party, like any private keys the relying party will use for signing AuthnRequests.
|
||||
*
|
||||
* Also note that an {@code IDPSSODescriptor} typically only contains information
|
||||
* about the asserting party. Thus, you will need to remember to still populate
|
||||
* anything about the relying party, like any private keys the relying party will use
|
||||
* for signing AuthnRequests.
|
||||
* @param metadataLocation
|
||||
* @return the {@link RelyingPartyRegistration.Builder} for further configuration
|
||||
*/
|
||||
public static RelyingPartyRegistration.Builder fromMetadataLocation(String metadataLocation) {
|
||||
try {
|
||||
return rest.getForObject(metadataLocation, RelyingPartyRegistration.Builder.class);
|
||||
} catch (RestClientException e) {
|
||||
}
|
||||
catch (RestClientException e) {
|
||||
if (e.getCause() instanceof Saml2Exception) {
|
||||
throw (Saml2Exception) e.getCause();
|
||||
}
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-7
@@ -17,17 +17,17 @@
|
||||
package org.springframework.security.saml2.provider.service.registration;
|
||||
|
||||
/**
|
||||
* The type of bindings that messages are exchanged using
|
||||
* Supported bindings are {@code urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST}
|
||||
* and {@code urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect}.
|
||||
* In addition there is support for {@code urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect}
|
||||
* with an XML signature in the message rather than query parameters.
|
||||
* The type of bindings that messages are exchanged using Supported bindings are
|
||||
* {@code urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST} and
|
||||
* {@code urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect}. In addition there is
|
||||
* support for {@code urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect} with an XML
|
||||
* signature in the message rather than query parameters.
|
||||
* @since 5.3
|
||||
*/
|
||||
public enum Saml2MessageBinding {
|
||||
|
||||
POST("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"),
|
||||
REDIRECT("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect");
|
||||
POST("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"), REDIRECT(
|
||||
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect");
|
||||
|
||||
private final String urn;
|
||||
|
||||
@@ -42,4 +42,5 @@ public enum Saml2MessageBinding {
|
||||
public String getUrn() {
|
||||
return urn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-20
@@ -40,12 +40,14 @@ import static org.springframework.util.StringUtils.hasText;
|
||||
public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
public static final String DEFAULT_FILTER_PROCESSES_URI = "/login/saml2/sso/{registrationId}";
|
||||
|
||||
private final AuthenticationConverter authenticationConverter;
|
||||
|
||||
/**
|
||||
* Creates a {@code Saml2WebSsoAuthenticationFilter} authentication filter that is configured
|
||||
* to use the {@link #DEFAULT_FILTER_PROCESSES_URI} processing URL
|
||||
* @param relyingPartyRegistrationRepository - repository of configured SAML 2 entities. Required.
|
||||
* Creates a {@code Saml2WebSsoAuthenticationFilter} authentication filter that is
|
||||
* configured to use the {@link #DEFAULT_FILTER_PROCESSES_URI} processing URL
|
||||
* @param relyingPartyRegistrationRepository - repository of configured SAML 2
|
||||
* entities. Required.
|
||||
*/
|
||||
public Saml2WebSsoAuthenticationFilter(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||
this(relyingPartyRegistrationRepository, DEFAULT_FILTER_PROCESSES_URI);
|
||||
@@ -53,35 +55,32 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce
|
||||
|
||||
/**
|
||||
* Creates a {@code Saml2WebSsoAuthenticationFilter} authentication filter
|
||||
* @param relyingPartyRegistrationRepository - repository of configured SAML 2 entities. Required.
|
||||
* @param filterProcessesUrl the processing URL, must contain a {registrationId} variable. Required.
|
||||
* @param relyingPartyRegistrationRepository - repository of configured SAML 2
|
||||
* entities. Required.
|
||||
* @param filterProcessesUrl the processing URL, must contain a {registrationId}
|
||||
* variable. Required.
|
||||
*/
|
||||
public Saml2WebSsoAuthenticationFilter(
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository,
|
||||
public Saml2WebSsoAuthenticationFilter(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository,
|
||||
String filterProcessesUrl) {
|
||||
this(new Saml2AuthenticationTokenConverter
|
||||
(new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository)),
|
||||
filterProcessesUrl);
|
||||
this(new Saml2AuthenticationTokenConverter(
|
||||
new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository)), filterProcessesUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Saml2WebSsoAuthenticationFilter} given the provided parameters
|
||||
*
|
||||
* @param authenticationConverter the strategy for converting an {@link HttpServletRequest}
|
||||
* into an {@link Authentication}
|
||||
* @param filterProcessingUrl the processing URL, must contain a {registrationId} variable
|
||||
* @param authenticationConverter the strategy for converting an
|
||||
* {@link HttpServletRequest} into an {@link Authentication}
|
||||
* @param filterProcessingUrl the processing URL, must contain a {registrationId}
|
||||
* variable
|
||||
* @since 5.4
|
||||
*/
|
||||
public Saml2WebSsoAuthenticationFilter(
|
||||
AuthenticationConverter authenticationConverter,
|
||||
public Saml2WebSsoAuthenticationFilter(AuthenticationConverter authenticationConverter,
|
||||
String filterProcessingUrl) {
|
||||
super(filterProcessingUrl);
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
Assert.hasText(filterProcessingUrl, "filterProcessesUrl must contain a URL pattern");
|
||||
Assert.isTrue(
|
||||
filterProcessingUrl.contains("{registrationId}"),
|
||||
"filterProcessesUrl must contain a {registrationId} match variable"
|
||||
);
|
||||
Assert.isTrue(filterProcessingUrl.contains("{registrationId}"),
|
||||
"filterProcessesUrl must contain a {registrationId} match variable");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
setAllowSessionCreation(true);
|
||||
setSessionAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy());
|
||||
@@ -103,4 +102,5 @@ public class Saml2WebSsoAuthenticationFilter extends AbstractAuthenticationProce
|
||||
}
|
||||
return getAuthenticationManager().authenticate(authentication);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+49
-65
@@ -47,22 +47,22 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
|
||||
/**
|
||||
* This {@code Filter} formulates a
|
||||
* <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf">SAML 2.0 AuthnRequest</a> (line 1968)
|
||||
* and redirects to a configured asserting party.
|
||||
* <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf">SAML 2.0
|
||||
* AuthnRequest</a> (line 1968) and redirects to a configured asserting party.
|
||||
*
|
||||
* <p>
|
||||
* It supports the
|
||||
* <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf">HTTP-Redirect</a> (line 520)
|
||||
* and
|
||||
* <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf">HTTP-POST</a> (line 753)
|
||||
* bindings.
|
||||
* It supports the <a href=
|
||||
* "https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf">HTTP-Redirect</a>
|
||||
* (line 520) and <a href=
|
||||
* "https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf">HTTP-POST</a>
|
||||
* (line 753) bindings.
|
||||
*
|
||||
* <p>
|
||||
* By default, this {@code Filter} responds to authentication requests
|
||||
* at the {@code URI} {@code /oauth2/authorization/{registrationId}}.
|
||||
* The {@code URI} template variable {@code {registrationId}} represents the
|
||||
* {@link RelyingPartyRegistration#getRegistrationId() registration identifier} of the relying party
|
||||
* that is used for initiating the authentication request.
|
||||
* By default, this {@code Filter} responds to authentication requests at the {@code URI}
|
||||
* {@code /oauth2/authorization/{registrationId}}. The {@code URI} template variable
|
||||
* {@code {registrationId}} represents the
|
||||
* {@link RelyingPartyRegistration#getRegistrationId() registration identifier} of the
|
||||
* relying party that is used for initiating the authentication request.
|
||||
*
|
||||
* @since 5.2
|
||||
* @author Filip Hanik
|
||||
@@ -71,27 +71,32 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter {
|
||||
|
||||
private final Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver;
|
||||
|
||||
private Saml2AuthenticationRequestFactory authenticationRequestFactory;
|
||||
|
||||
private RequestMatcher redirectMatcher = new AntPathRequestMatcher("/saml2/authenticate/{registrationId}");
|
||||
|
||||
/**
|
||||
* Construct a {@link Saml2WebSsoAuthenticationRequestFilter} with the provided parameters
|
||||
*
|
||||
* @param relyingPartyRegistrationRepository a repository for relying party configurations
|
||||
* @deprecated use the constructor that takes a {@link Saml2AuthenticationRequestFactory}
|
||||
* Construct a {@link Saml2WebSsoAuthenticationRequestFilter} with the provided
|
||||
* parameters
|
||||
* @param relyingPartyRegistrationRepository a repository for relying party
|
||||
* configurations
|
||||
* @deprecated use the constructor that takes a
|
||||
* {@link Saml2AuthenticationRequestFactory}
|
||||
*/
|
||||
@Deprecated
|
||||
public Saml2WebSsoAuthenticationRequestFilter(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||
public Saml2WebSsoAuthenticationRequestFilter(
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||
this(new DefaultSaml2AuthenticationRequestContextResolver(
|
||||
new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository)),
|
||||
new org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationRequestFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link Saml2WebSsoAuthenticationRequestFilter} with the provided parameters
|
||||
*
|
||||
* @param authenticationRequestContextResolver a strategy for formulating a {@link Saml2AuthenticationRequestContext}
|
||||
* Construct a {@link Saml2WebSsoAuthenticationRequestFilter} with the provided
|
||||
* parameters
|
||||
* @param authenticationRequestContextResolver a strategy for formulating a
|
||||
* {@link Saml2AuthenticationRequestContext}
|
||||
* @since 5.4
|
||||
*/
|
||||
public Saml2WebSsoAuthenticationRequestFilter(
|
||||
@@ -105,9 +110,10 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given {@link Saml2AuthenticationRequestFactory} for formulating the SAML 2.0 AuthnRequest
|
||||
*
|
||||
* @param authenticationRequestFactory the {@link Saml2AuthenticationRequestFactory} to use
|
||||
* Use the given {@link Saml2AuthenticationRequestFactory} for formulating the SAML
|
||||
* 2.0 AuthnRequest
|
||||
* @param authenticationRequestFactory the {@link Saml2AuthenticationRequestFactory}
|
||||
* to use
|
||||
* @deprecated use the constructor instead
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -118,7 +124,6 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter
|
||||
|
||||
/**
|
||||
* Use the given {@link RequestMatcher} that activates this filter for a given request
|
||||
*
|
||||
* @param redirectMatcher the {@link RequestMatcher} to use
|
||||
*/
|
||||
public void setRedirectMatcher(RequestMatcher redirectMatcher) {
|
||||
@@ -147,41 +152,36 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter
|
||||
RelyingPartyRegistration relyingParty = context.getRelyingPartyRegistration();
|
||||
if (relyingParty.getAssertingPartyDetails().getSingleSignOnServiceBinding() == Saml2MessageBinding.REDIRECT) {
|
||||
sendRedirect(response, context);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sendPost(response, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendRedirect(HttpServletResponse response, Saml2AuthenticationRequestContext context)
|
||||
throws IOException {
|
||||
Saml2RedirectAuthenticationRequest authenticationRequest =
|
||||
this.authenticationRequestFactory.createRedirectAuthenticationRequest(context);
|
||||
Saml2RedirectAuthenticationRequest authenticationRequest = this.authenticationRequestFactory
|
||||
.createRedirectAuthenticationRequest(context);
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder
|
||||
.fromUriString(authenticationRequest.getAuthenticationRequestUri());
|
||||
addParameter("SAMLRequest", authenticationRequest.getSamlRequest(), uriBuilder);
|
||||
addParameter("RelayState", authenticationRequest.getRelayState(), uriBuilder);
|
||||
addParameter("SigAlg", authenticationRequest.getSigAlg(), uriBuilder);
|
||||
addParameter("Signature", authenticationRequest.getSignature(), uriBuilder);
|
||||
String redirectUrl = uriBuilder
|
||||
.build(true)
|
||||
.toUriString();
|
||||
String redirectUrl = uriBuilder.build(true).toUriString();
|
||||
response.sendRedirect(redirectUrl);
|
||||
}
|
||||
|
||||
private void addParameter(String name, String value, UriComponentsBuilder builder) {
|
||||
Assert.hasText(name, "name cannot be empty or null");
|
||||
if (StringUtils.hasText(value)) {
|
||||
builder.queryParam(
|
||||
UriUtils.encode(name, ISO_8859_1),
|
||||
UriUtils.encode(value, ISO_8859_1)
|
||||
);
|
||||
builder.queryParam(UriUtils.encode(name, ISO_8859_1), UriUtils.encode(value, ISO_8859_1));
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPost(HttpServletResponse response, Saml2AuthenticationRequestContext context)
|
||||
throws IOException {
|
||||
Saml2PostAuthenticationRequest authenticationRequest =
|
||||
this.authenticationRequestFactory.createPostAuthenticationRequest(context);
|
||||
private void sendPost(HttpServletResponse response, Saml2AuthenticationRequestContext context) throws IOException {
|
||||
Saml2PostAuthenticationRequest authenticationRequest = this.authenticationRequestFactory
|
||||
.createPostAuthenticationRequest(context);
|
||||
String html = createSamlPostRequestFormData(authenticationRequest);
|
||||
response.setContentType(MediaType.TEXT_HTML_VALUE);
|
||||
response.getWriter().write(html);
|
||||
@@ -191,42 +191,26 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter
|
||||
String authenticationRequestUri = authenticationRequest.getAuthenticationRequestUri();
|
||||
String relayState = authenticationRequest.getRelayState();
|
||||
String samlRequest = authenticationRequest.getSamlRequest();
|
||||
StringBuilder postHtml = new StringBuilder()
|
||||
.append("<!DOCTYPE html>\n")
|
||||
.append("<html>\n")
|
||||
.append(" <head>\n")
|
||||
.append(" <meta charset=\"utf-8\" />\n")
|
||||
.append(" </head>\n")
|
||||
.append(" <body onload=\"document.forms[0].submit()\">\n")
|
||||
.append(" <noscript>\n")
|
||||
StringBuilder postHtml = new StringBuilder().append("<!DOCTYPE html>\n").append("<html>\n")
|
||||
.append(" <head>\n").append(" <meta charset=\"utf-8\" />\n").append(" </head>\n")
|
||||
.append(" <body onload=\"document.forms[0].submit()\">\n").append(" <noscript>\n")
|
||||
.append(" <p>\n")
|
||||
.append(" <strong>Note:</strong> Since your browser does not support JavaScript,\n")
|
||||
.append(" you must press the Continue button once to proceed.\n")
|
||||
.append(" </p>\n")
|
||||
.append(" </noscript>\n")
|
||||
.append(" \n")
|
||||
.append(" </p>\n").append(" </noscript>\n").append(" \n")
|
||||
.append(" <form action=\"").append(authenticationRequestUri).append("\" method=\"post\">\n")
|
||||
.append(" <div>\n")
|
||||
.append(" <input type=\"hidden\" name=\"SAMLRequest\" value=\"")
|
||||
.append(HtmlUtils.htmlEscape(samlRequest))
|
||||
.append("\"/>\n");
|
||||
.append(HtmlUtils.htmlEscape(samlRequest)).append("\"/>\n");
|
||||
if (StringUtils.hasText(relayState)) {
|
||||
postHtml
|
||||
.append(" <input type=\"hidden\" name=\"RelayState\" value=\"")
|
||||
.append(HtmlUtils.htmlEscape(relayState))
|
||||
.append("\"/>\n");
|
||||
postHtml.append(" <input type=\"hidden\" name=\"RelayState\" value=\"")
|
||||
.append(HtmlUtils.htmlEscape(relayState)).append("\"/>\n");
|
||||
}
|
||||
postHtml
|
||||
.append(" </div>\n")
|
||||
.append(" <noscript>\n")
|
||||
.append(" <div>\n")
|
||||
postHtml.append(" </div>\n").append(" <noscript>\n").append(" <div>\n")
|
||||
.append(" <input type=\"submit\" value=\"Continue\"/>\n")
|
||||
.append(" </div>\n")
|
||||
.append(" </noscript>\n")
|
||||
.append(" </form>\n")
|
||||
.append(" \n")
|
||||
.append(" </body>\n")
|
||||
.append("</html>");
|
||||
.append(" </div>\n").append(" </noscript>\n").append(" </form>\n")
|
||||
.append(" \n").append(" </body>\n").append("</html>");
|
||||
return postHtml.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-23
@@ -37,8 +37,8 @@ import static org.springframework.web.util.UriComponentsBuilder.fromHttpUrl;
|
||||
|
||||
/**
|
||||
* A {@link Converter} that resolves a {@link RelyingPartyRegistration} by extracting the
|
||||
* registration id from the request, querying a {@link RelyingPartyRegistrationRepository},
|
||||
* and resolving any template values.
|
||||
* registration id from the request, querying a
|
||||
* {@link RelyingPartyRegistrationRepository}, and resolving any template values.
|
||||
*
|
||||
* @since 5.4
|
||||
* @author Josh Cummings
|
||||
@@ -49,10 +49,11 @@ public final class DefaultRelyingPartyRegistrationResolver
|
||||
private static final char PATH_DELIMITER = '/';
|
||||
|
||||
private final RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
|
||||
|
||||
private final Converter<HttpServletRequest, String> registrationIdResolver = new RegistrationIdResolver();
|
||||
|
||||
public DefaultRelyingPartyRegistrationResolver
|
||||
(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||
public DefaultRelyingPartyRegistrationResolver(
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
|
||||
|
||||
Assert.notNull(relyingPartyRegistrationRepository, "relyingPartyRegistrationRepository cannot be null");
|
||||
this.relyingPartyRegistrationRepository = relyingPartyRegistrationRepository;
|
||||
@@ -64,8 +65,8 @@ public final class DefaultRelyingPartyRegistrationResolver
|
||||
if (registrationId == null) {
|
||||
return null;
|
||||
}
|
||||
RelyingPartyRegistration relyingPartyRegistration =
|
||||
this.relyingPartyRegistrationRepository.findByRegistrationId(registrationId);
|
||||
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationRepository
|
||||
.findByRegistrationId(registrationId);
|
||||
if (relyingPartyRegistration == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -73,12 +74,10 @@ public final class DefaultRelyingPartyRegistrationResolver
|
||||
String applicationUri = getApplicationUri(request);
|
||||
Function<String, String> templateResolver = templateResolver(applicationUri, relyingPartyRegistration);
|
||||
String relyingPartyEntityId = templateResolver.apply(relyingPartyRegistration.getEntityId());
|
||||
String assertionConsumerServiceLocation = templateResolver.apply(
|
||||
relyingPartyRegistration.getAssertionConsumerServiceLocation());
|
||||
return withRelyingPartyRegistration(relyingPartyRegistration)
|
||||
.entityId(relyingPartyEntityId)
|
||||
.assertionConsumerServiceLocation(assertionConsumerServiceLocation)
|
||||
.build();
|
||||
String assertionConsumerServiceLocation = templateResolver
|
||||
.apply(relyingPartyRegistration.getAssertionConsumerServiceLocation());
|
||||
return withRelyingPartyRegistration(relyingPartyRegistration).entityId(relyingPartyEntityId)
|
||||
.assertionConsumerServiceLocation(assertionConsumerServiceLocation).build();
|
||||
}
|
||||
|
||||
private Function<String, String> templateResolver(String applicationUri, RelyingPartyRegistration relyingParty) {
|
||||
@@ -89,9 +88,7 @@ public final class DefaultRelyingPartyRegistrationResolver
|
||||
String entityId = relyingParty.getAssertingPartyDetails().getEntityId();
|
||||
String registrationId = relyingParty.getRegistrationId();
|
||||
Map<String, String> uriVariables = new HashMap<>();
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(baseUrl)
|
||||
.replaceQuery(null)
|
||||
.fragment(null)
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(baseUrl).replaceQuery(null).fragment(null)
|
||||
.build();
|
||||
String scheme = uriComponents.getScheme();
|
||||
uriVariables.put("baseScheme", scheme == null ? "" : scheme);
|
||||
@@ -109,21 +106,17 @@ public final class DefaultRelyingPartyRegistrationResolver
|
||||
uriVariables.put("entityId", StringUtils.hasText(entityId) ? entityId : "");
|
||||
uriVariables.put("registrationId", StringUtils.hasText(registrationId) ? registrationId : "");
|
||||
|
||||
return UriComponentsBuilder.fromUriString(template)
|
||||
.buildAndExpand(uriVariables)
|
||||
.toUriString();
|
||||
return UriComponentsBuilder.fromUriString(template).buildAndExpand(uriVariables).toUriString();
|
||||
}
|
||||
|
||||
private static String getApplicationUri(HttpServletRequest request) {
|
||||
UriComponents uriComponents = fromHttpUrl(buildFullRequestUrl(request))
|
||||
.replacePath(request.getContextPath())
|
||||
.replaceQuery(null)
|
||||
.fragment(null)
|
||||
.build();
|
||||
UriComponents uriComponents = fromHttpUrl(buildFullRequestUrl(request)).replacePath(request.getContextPath())
|
||||
.replaceQuery(null).fragment(null).build();
|
||||
return uriComponents.toUriString();
|
||||
}
|
||||
|
||||
private static class RegistrationIdResolver implements Converter<HttpServletRequest, String> {
|
||||
|
||||
private final RequestMatcher requestMatcher = new AntPathRequestMatcher("/**/{registrationId}");
|
||||
|
||||
@Override
|
||||
@@ -131,5 +124,7 @@ public final class DefaultRelyingPartyRegistrationResolver
|
||||
RequestMatcher.MatchResult result = this.requestMatcher.matcher(request);
|
||||
return result.getVariables().get("registrationId");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-13
@@ -27,21 +27,23 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The default implementation for {@link Saml2AuthenticationRequestContextResolver}
|
||||
* which uses the current request and given relying party to formulate a {@link Saml2AuthenticationRequestContext}
|
||||
* The default implementation for {@link Saml2AuthenticationRequestContextResolver} which
|
||||
* uses the current request and given relying party to formulate a
|
||||
* {@link Saml2AuthenticationRequestContext}
|
||||
*
|
||||
* @author Shazin Sadakath
|
||||
* @author Josh Cummings
|
||||
* @since 5.4
|
||||
*/
|
||||
public final class DefaultSaml2AuthenticationRequestContextResolver implements Saml2AuthenticationRequestContextResolver {
|
||||
public final class DefaultSaml2AuthenticationRequestContextResolver
|
||||
implements Saml2AuthenticationRequestContextResolver {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver;
|
||||
|
||||
public DefaultSaml2AuthenticationRequestContextResolver
|
||||
(Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver) {
|
||||
public DefaultSaml2AuthenticationRequestContextResolver(
|
||||
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver) {
|
||||
this.relyingPartyRegistrationResolver = relyingPartyRegistrationResolver;
|
||||
}
|
||||
|
||||
@@ -56,20 +58,19 @@ public final class DefaultSaml2AuthenticationRequestContextResolver implements S
|
||||
return null;
|
||||
}
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("Creating SAML 2.0 Authentication Request for Asserting Party [" +
|
||||
relyingParty.getRegistrationId() + "]");
|
||||
this.logger.debug("Creating SAML 2.0 Authentication Request for Asserting Party ["
|
||||
+ relyingParty.getRegistrationId() + "]");
|
||||
}
|
||||
return createRedirectAuthenticationRequestContext(request, relyingParty);
|
||||
}
|
||||
|
||||
private Saml2AuthenticationRequestContext createRedirectAuthenticationRequestContext(
|
||||
HttpServletRequest request, RelyingPartyRegistration relyingParty) {
|
||||
private Saml2AuthenticationRequestContext createRedirectAuthenticationRequestContext(HttpServletRequest request,
|
||||
RelyingPartyRegistration relyingParty) {
|
||||
|
||||
return Saml2AuthenticationRequestContext.builder()
|
||||
.issuer(relyingParty.getEntityId())
|
||||
return Saml2AuthenticationRequestContext.builder().issuer(relyingParty.getEntityId())
|
||||
.relyingPartyRegistration(relyingParty)
|
||||
.assertionConsumerServiceUrl(relyingParty.getAssertionConsumerServiceLocation())
|
||||
.relayState(request.getParameter("RelayState"))
|
||||
.build();
|
||||
.relayState(request.getParameter("RelayState")).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-4
@@ -22,7 +22,8 @@ import org.springframework.security.saml2.provider.service.authentication.Saml2A
|
||||
|
||||
/**
|
||||
* This {@code Saml2AuthenticationRequestContextResolver} formulates a
|
||||
* <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf">SAML 2.0 AuthnRequest</a> (line 1968)
|
||||
* <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf">SAML 2.0
|
||||
* AuthnRequest</a> (line 1968)
|
||||
*
|
||||
* @author Shazin Sadakath
|
||||
* @author Josh Cummings
|
||||
@@ -31,11 +32,11 @@ import org.springframework.security.saml2.provider.service.authentication.Saml2A
|
||||
public interface Saml2AuthenticationRequestContextResolver {
|
||||
|
||||
/**
|
||||
* This {@code resolve} method is defined to create a {@link Saml2AuthenticationRequestContext}
|
||||
*
|
||||
*
|
||||
* This {@code resolve} method is defined to create a
|
||||
* {@link Saml2AuthenticationRequestContext}
|
||||
* @param request the current request
|
||||
* @return the created {@link Saml2AuthenticationRequestContext} for the request
|
||||
*/
|
||||
Saml2AuthenticationRequestContext resolve(HttpServletRequest request);
|
||||
|
||||
}
|
||||
|
||||
+10
-8
@@ -35,26 +35,27 @@ import org.springframework.util.Assert;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationConverter} that generates a {@link Saml2AuthenticationToken} appropriate
|
||||
* for authenticated a SAML 2.0 Assertion against an
|
||||
* An {@link AuthenticationConverter} that generates a {@link Saml2AuthenticationToken}
|
||||
* appropriate for authenticated a SAML 2.0 Assertion against an
|
||||
* {@link org.springframework.security.authentication.AuthenticationManager}.
|
||||
*
|
||||
* @author Josh Cummings
|
||||
* @since 5.4
|
||||
*/
|
||||
public final class Saml2AuthenticationTokenConverter implements AuthenticationConverter {
|
||||
private static Base64 BASE64 = new Base64(0, new byte[]{'\n'});
|
||||
|
||||
private static Base64 BASE64 = new Base64(0, new byte[] { '\n' });
|
||||
|
||||
private final Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver;
|
||||
|
||||
/**
|
||||
* Constructs a {@link Saml2AuthenticationTokenConverter} given a strategy for resolving
|
||||
* Constructs a {@link Saml2AuthenticationTokenConverter} given a strategy for
|
||||
* resolving {@link RelyingPartyRegistration}s
|
||||
* @param relyingPartyRegistrationResolver the strategy for resolving
|
||||
* {@link RelyingPartyRegistration}s
|
||||
*
|
||||
* @param relyingPartyRegistrationResolver the strategy for resolving {@link RelyingPartyRegistration}s
|
||||
*/
|
||||
public Saml2AuthenticationTokenConverter
|
||||
(Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver) {
|
||||
public Saml2AuthenticationTokenConverter(
|
||||
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver) {
|
||||
Assert.notNull(relyingPartyRegistrationResolver, "relyingPartyRegistrationResolver cannot be null");
|
||||
this.relyingPartyRegistrationResolver = relyingPartyRegistrationResolver;
|
||||
}
|
||||
@@ -102,4 +103,5 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo
|
||||
throw new Saml2Exception("Unable to inflate string", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -42,6 +42,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
||||
public final class Saml2MetadataFilter extends OncePerRequestFilter {
|
||||
|
||||
private final Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationConverter;
|
||||
|
||||
private final Saml2MetadataResolver saml2MetadataResolver;
|
||||
|
||||
private RequestMatcher requestMatcher = new AntPathRequestMatcher(
|
||||
@@ -65,8 +66,7 @@ public final class Saml2MetadataFilter extends OncePerRequestFilter {
|
||||
return;
|
||||
}
|
||||
|
||||
RelyingPartyRegistration relyingPartyRegistration =
|
||||
this.relyingPartyRegistrationConverter.convert(request);
|
||||
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationConverter.convert(request);
|
||||
if (relyingPartyRegistration == null) {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
return;
|
||||
@@ -88,13 +88,13 @@ public final class Saml2MetadataFilter extends OncePerRequestFilter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link RequestMatcher} that determines whether this filter should
|
||||
* handle the incoming {@link HttpServletRequest}
|
||||
*
|
||||
* Set the {@link RequestMatcher} that determines whether this filter should handle
|
||||
* the incoming {@link HttpServletRequest}
|
||||
* @param requestMatcher
|
||||
*/
|
||||
public void setRequestMatcher(RequestMatcher requestMatcher) {
|
||||
Assert.notNull(requestMatcher, "requestMatcher cannot be null");
|
||||
this.requestMatcher = requestMatcher;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -37,8 +37,8 @@ public class OpenSamlInitializationServiceTests {
|
||||
OpenSamlInitializationService.initialize();
|
||||
XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class);
|
||||
assertThat(registry.getParserPool()).isNotNull();
|
||||
assertThatCode(() -> OpenSamlInitializationService.requireInitialize(r -> {}))
|
||||
.isInstanceOf(Saml2Exception.class)
|
||||
.hasMessageContaining("OpenSAML was already initialized previously");
|
||||
assertThatCode(() -> OpenSamlInitializationService.requireInitialize(r -> {
|
||||
})).isInstanceOf(Saml2Exception.class).hasMessageContaining("OpenSAML was already initialized previously");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -32,7 +32,7 @@ import static java.util.zip.Deflater.DEFLATED;
|
||||
|
||||
public final class Saml2Utils {
|
||||
|
||||
private static Base64 BASE64 = new Base64(0, new byte[]{'\n'});
|
||||
private static Base64 BASE64 = new Base64(0, new byte[] { '\n' });
|
||||
|
||||
public static String samlEncode(byte[] b) {
|
||||
return BASE64.encodeAsString(b);
|
||||
@@ -67,4 +67,5 @@ public final class Saml2Utils {
|
||||
throw new Saml2Exception("Unable to inflate string", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
-32
@@ -40,44 +40,43 @@ public class Saml2X509CredentialTests {
|
||||
public ExpectedException exception = ExpectedException.none();
|
||||
|
||||
private PrivateKey key;
|
||||
|
||||
private X509Certificate certificate;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
String keyData = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n" +
|
||||
"VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n" +
|
||||
"cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n" +
|
||||
"Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n" +
|
||||
"x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n" +
|
||||
"wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n" +
|
||||
"vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n" +
|
||||
"8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n" +
|
||||
"oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n" +
|
||||
"EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n" +
|
||||
"KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n" +
|
||||
"YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n" +
|
||||
"9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" +
|
||||
"INrtuLp4YHbgk1mi\n" +
|
||||
"-----END PRIVATE KEY-----";
|
||||
String keyData = "-----BEGIN PRIVATE KEY-----\n"
|
||||
+ "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n"
|
||||
+ "VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n"
|
||||
+ "cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n"
|
||||
+ "Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n"
|
||||
+ "x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n"
|
||||
+ "wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n"
|
||||
+ "vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n"
|
||||
+ "8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n"
|
||||
+ "oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n"
|
||||
+ "EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n"
|
||||
+ "KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n"
|
||||
+ "YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n"
|
||||
+ "9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" + "INrtuLp4YHbgk1mi\n"
|
||||
+ "-----END PRIVATE KEY-----";
|
||||
key = RsaKeyConverters.pkcs8().convert(new ByteArrayInputStream(keyData.getBytes(UTF_8)));
|
||||
final CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
String certificateData = "-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n" +
|
||||
"VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n" +
|
||||
"A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n" +
|
||||
"DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n" +
|
||||
"MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n" +
|
||||
"MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n" +
|
||||
"TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n" +
|
||||
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n" +
|
||||
"vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n" +
|
||||
"+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n" +
|
||||
"y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n" +
|
||||
"XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n" +
|
||||
"qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n" +
|
||||
"RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
String certificateData = "-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n"
|
||||
+ "VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n"
|
||||
+ "A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n"
|
||||
+ "DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n"
|
||||
+ "MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n"
|
||||
+ "MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n"
|
||||
+ "TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n"
|
||||
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n"
|
||||
+ "vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n"
|
||||
+ "+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n"
|
||||
+ "y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n"
|
||||
+ "XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n"
|
||||
+ "qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n"
|
||||
+ "RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" + "-----END CERTIFICATE-----";
|
||||
certificate = (X509Certificate) factory
|
||||
.generateCertificate(new ByteArrayInputStream(certificateData.getBytes(UTF_8)));
|
||||
}
|
||||
@@ -195,4 +194,5 @@ public class Saml2X509CredentialTests {
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
Saml2X509Credential.encryption(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+83
-88
@@ -34,6 +34,7 @@ import static org.springframework.security.saml2.core.Saml2X509Credential.Saml2X
|
||||
import static org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION;
|
||||
|
||||
public final class TestSaml2X509Credentials {
|
||||
|
||||
public static Saml2X509Credential assertingPartySigningCredential() {
|
||||
return new Saml2X509Credential(idpPrivateKey(), idpCertificate(), SIGNING);
|
||||
}
|
||||
@@ -61,9 +62,7 @@ public final class TestSaml2X509Credentials {
|
||||
private static X509Certificate certificate(String cert) {
|
||||
ByteArrayInputStream certBytes = new ByteArrayInputStream(cert.getBytes());
|
||||
try {
|
||||
return (X509Certificate) CertificateFactory
|
||||
.getInstance("X.509")
|
||||
.generateCertificate(certBytes);
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certBytes);
|
||||
}
|
||||
catch (CertificateException e) {
|
||||
throw new Saml2Exception(e);
|
||||
@@ -79,101 +78,97 @@ public final class TestSaml2X509Credentials {
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate idpCertificate() {
|
||||
return certificate("-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD\n"
|
||||
+ "VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD\n"
|
||||
+ "VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX\n"
|
||||
+ "c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw\n"
|
||||
+ "aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ\n"
|
||||
+ "BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa\n"
|
||||
+ "BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD\n"
|
||||
+ "DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr\n"
|
||||
+ "QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62\n"
|
||||
+ "E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz\n"
|
||||
+ "2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW\n"
|
||||
+ "RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ\n"
|
||||
+ "nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5\n"
|
||||
+ "cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph\n"
|
||||
+ "iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5\n"
|
||||
+ "ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD\n"
|
||||
+ "AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO\n"
|
||||
+ "nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v\n"
|
||||
+ "ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu\n"
|
||||
+ "xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z\n"
|
||||
+ "V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3\n"
|
||||
+ "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n"
|
||||
+ "-----END CERTIFICATE-----\n");
|
||||
private static X509Certificate idpCertificate() {
|
||||
return certificate(
|
||||
"-----BEGIN CERTIFICATE-----\n" + "MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD\n"
|
||||
+ "VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD\n"
|
||||
+ "VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX\n"
|
||||
+ "c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw\n"
|
||||
+ "aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ\n"
|
||||
+ "BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa\n"
|
||||
+ "BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD\n"
|
||||
+ "DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr\n"
|
||||
+ "QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62\n"
|
||||
+ "E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz\n"
|
||||
+ "2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW\n"
|
||||
+ "RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ\n"
|
||||
+ "nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5\n"
|
||||
+ "cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph\n"
|
||||
+ "iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5\n"
|
||||
+ "ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD\n"
|
||||
+ "AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO\n"
|
||||
+ "nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v\n"
|
||||
+ "ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu\n"
|
||||
+ "xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z\n"
|
||||
+ "V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3\n"
|
||||
+ "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n" + "-----END CERTIFICATE-----\n");
|
||||
}
|
||||
|
||||
|
||||
private static PrivateKey idpPrivateKey() {
|
||||
return privateKey("-----BEGIN PRIVATE KEY-----\n"
|
||||
+ "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4cn62E1xLqpN3\n"
|
||||
+ "4PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZX\n"
|
||||
+ "W+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHE\n"
|
||||
+ "fDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7h\n"
|
||||
+ "Z6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/T\n"
|
||||
+ "Xy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7\n"
|
||||
+ "I+J5lS8VAgMBAAECggEBAKyxBlIS7mcp3chvq0RF7B3PHFJMMzkwE+t3pLJcs4cZ\n"
|
||||
+ "nezh/KbREfP70QjXzk/llnZCvxeIs5vRu24vbdBm79qLHqBuHp8XfHHtuo2AfoAQ\n"
|
||||
+ "l4h047Xc/+TKMivnPQ0jX9qqndKDLqZDf5wnbslDmlskvF0a/MjsLU0TxtOfo+dB\n"
|
||||
+ "t55FW11cGqxZwhS5Gnr+cbw3OkHz23b9gEOt9qfwPVepeysbmm9FjU+k4yVa7rAN\n"
|
||||
+ "xcbzVb6Y7GCITe2tgvvEHmjB9BLmWrH3mZ3Af17YU/iN6TrpPd6Sj3QoS+2wGtAe\n"
|
||||
+ "HbUs3CKJu7bIHcj4poal6Kh8519S+erJTtqQ8M0ZiEECgYEA43hLYAPaUueFkdfh\n"
|
||||
+ "9K/7ClH6436CUH3VdizwUXi26fdhhV/I/ot6zLfU2mgEHU22LBECWQGtAFm8kv0P\n"
|
||||
+ "zPn+qjaR3e62l5PIlSYbnkIidzoDZ2ztu4jF5LgStlTJQPteFEGgZVl5o9DaSZOq\n"
|
||||
+ "Yd7G3XqXuQ1VGMW58G5FYJPtA1cCgYEAz5TPUtK+R2KXHMjUwlGY9AefQYRYmyX2\n"
|
||||
+ "Tn/OFgKvY8lpAkMrhPKONq7SMYc8E9v9G7A0dIOXvW7QOYSapNhKU+np3lUafR5F\n"
|
||||
+ "4ZN0bxZ9qjHbn3AMYeraKjeutHvlLtbHdIc1j3sxe/EzltRsYmiqLdEBW0p6hwWg\n"
|
||||
+ "tyGhYWVyaXMCgYAfDOKtHpmEy5nOCLwNXKBWDk7DExfSyPqEgSnk1SeS1HP5ctPK\n"
|
||||
+ "+1st6sIhdiVpopwFc+TwJWxqKdW18tlfT5jVv1E2DEnccw3kXilS9xAhWkfwrEvf\n"
|
||||
+ "V5I74GydewFl32o+NZ8hdo9GL1I8zO1rIq/et8dSOWGuWf9BtKu/vTGTTQKBgFxU\n"
|
||||
+ "VjsCnbvmsEwPUAL2hE/WrBFaKocnxXx5AFNt8lEyHtDwy4Sg1nygGcIJ4sD6koQk\n"
|
||||
+ "RdClT3LkvR04TAiSY80bN/i6ZcPNGUwSaDGZEWAIOSWbkwZijZNFnSGOEgxZX/IG\n"
|
||||
+ "yd39766vREEMTwEeiMNEOZQ/dmxkJm4OOVe25cLdAoGACOtPnq1Fxay80UYBf4rQ\n"
|
||||
+ "+bJ9yX1ulB8WIree1hD7OHSB2lRHxrVYWrglrTvkh63Lgx+EcsTV788OsvAVfPPz\n"
|
||||
+ "BZrn8SdDlQqalMxUBYEFwnsYD3cQ8yOUnijFVC4xNcdDv8OIqVgSk4KKxU5AshaA\n" + "xk6Mox+u8Cc2eAK12H13i+8=\n"
|
||||
+ "-----END PRIVATE KEY-----\n");
|
||||
return privateKey(
|
||||
"-----BEGIN PRIVATE KEY-----\n" + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4cn62E1xLqpN3\n"
|
||||
+ "4PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZX\n"
|
||||
+ "W+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHE\n"
|
||||
+ "fDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7h\n"
|
||||
+ "Z6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/T\n"
|
||||
+ "Xy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7\n"
|
||||
+ "I+J5lS8VAgMBAAECggEBAKyxBlIS7mcp3chvq0RF7B3PHFJMMzkwE+t3pLJcs4cZ\n"
|
||||
+ "nezh/KbREfP70QjXzk/llnZCvxeIs5vRu24vbdBm79qLHqBuHp8XfHHtuo2AfoAQ\n"
|
||||
+ "l4h047Xc/+TKMivnPQ0jX9qqndKDLqZDf5wnbslDmlskvF0a/MjsLU0TxtOfo+dB\n"
|
||||
+ "t55FW11cGqxZwhS5Gnr+cbw3OkHz23b9gEOt9qfwPVepeysbmm9FjU+k4yVa7rAN\n"
|
||||
+ "xcbzVb6Y7GCITe2tgvvEHmjB9BLmWrH3mZ3Af17YU/iN6TrpPd6Sj3QoS+2wGtAe\n"
|
||||
+ "HbUs3CKJu7bIHcj4poal6Kh8519S+erJTtqQ8M0ZiEECgYEA43hLYAPaUueFkdfh\n"
|
||||
+ "9K/7ClH6436CUH3VdizwUXi26fdhhV/I/ot6zLfU2mgEHU22LBECWQGtAFm8kv0P\n"
|
||||
+ "zPn+qjaR3e62l5PIlSYbnkIidzoDZ2ztu4jF5LgStlTJQPteFEGgZVl5o9DaSZOq\n"
|
||||
+ "Yd7G3XqXuQ1VGMW58G5FYJPtA1cCgYEAz5TPUtK+R2KXHMjUwlGY9AefQYRYmyX2\n"
|
||||
+ "Tn/OFgKvY8lpAkMrhPKONq7SMYc8E9v9G7A0dIOXvW7QOYSapNhKU+np3lUafR5F\n"
|
||||
+ "4ZN0bxZ9qjHbn3AMYeraKjeutHvlLtbHdIc1j3sxe/EzltRsYmiqLdEBW0p6hwWg\n"
|
||||
+ "tyGhYWVyaXMCgYAfDOKtHpmEy5nOCLwNXKBWDk7DExfSyPqEgSnk1SeS1HP5ctPK\n"
|
||||
+ "+1st6sIhdiVpopwFc+TwJWxqKdW18tlfT5jVv1E2DEnccw3kXilS9xAhWkfwrEvf\n"
|
||||
+ "V5I74GydewFl32o+NZ8hdo9GL1I8zO1rIq/et8dSOWGuWf9BtKu/vTGTTQKBgFxU\n"
|
||||
+ "VjsCnbvmsEwPUAL2hE/WrBFaKocnxXx5AFNt8lEyHtDwy4Sg1nygGcIJ4sD6koQk\n"
|
||||
+ "RdClT3LkvR04TAiSY80bN/i6ZcPNGUwSaDGZEWAIOSWbkwZijZNFnSGOEgxZX/IG\n"
|
||||
+ "yd39766vREEMTwEeiMNEOZQ/dmxkJm4OOVe25cLdAoGACOtPnq1Fxay80UYBf4rQ\n"
|
||||
+ "+bJ9yX1ulB8WIree1hD7OHSB2lRHxrVYWrglrTvkh63Lgx+EcsTV788OsvAVfPPz\n"
|
||||
+ "BZrn8SdDlQqalMxUBYEFwnsYD3cQ8yOUnijFVC4xNcdDv8OIqVgSk4KKxU5AshaA\n"
|
||||
+ "xk6Mox+u8Cc2eAK12H13i+8=\n" + "-----END PRIVATE KEY-----\n");
|
||||
}
|
||||
|
||||
private static X509Certificate spCertificate() {
|
||||
|
||||
return certificate("-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n" +
|
||||
"VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n" +
|
||||
"A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n" +
|
||||
"DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n" +
|
||||
"MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n" +
|
||||
"MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n" +
|
||||
"TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n" +
|
||||
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n" +
|
||||
"vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n" +
|
||||
"+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n" +
|
||||
"y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n" +
|
||||
"XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n" +
|
||||
"qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n" +
|
||||
"RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" +
|
||||
"-----END CERTIFICATE-----");
|
||||
return certificate(
|
||||
"-----BEGIN CERTIFICATE-----\n" + "MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n"
|
||||
+ "VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n"
|
||||
+ "A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n"
|
||||
+ "DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n"
|
||||
+ "MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n"
|
||||
+ "MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n"
|
||||
+ "TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n"
|
||||
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n"
|
||||
+ "vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n"
|
||||
+ "+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n"
|
||||
+ "y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n"
|
||||
+ "XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n"
|
||||
+ "qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n"
|
||||
+ "RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" + "-----END CERTIFICATE-----");
|
||||
}
|
||||
|
||||
private static PrivateKey spPrivateKey() {
|
||||
return privateKey("-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n" +
|
||||
"VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n" +
|
||||
"cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n" +
|
||||
"Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n" +
|
||||
"x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n" +
|
||||
"wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n" +
|
||||
"vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n" +
|
||||
"8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n" +
|
||||
"oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n" +
|
||||
"EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n" +
|
||||
"KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n" +
|
||||
"YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n" +
|
||||
"9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" +
|
||||
"INrtuLp4YHbgk1mi\n" +
|
||||
"-----END PRIVATE KEY-----");
|
||||
return privateKey(
|
||||
"-----BEGIN PRIVATE KEY-----\n" + "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n"
|
||||
+ "VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n"
|
||||
+ "cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n"
|
||||
+ "Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n"
|
||||
+ "x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n"
|
||||
+ "wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n"
|
||||
+ "vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n"
|
||||
+ "8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n"
|
||||
+ "oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n"
|
||||
+ "EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n"
|
||||
+ "KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n"
|
||||
+ "YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n"
|
||||
+ "9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" + "INrtuLp4YHbgk1mi\n"
|
||||
+ "-----END PRIVATE KEY-----");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
-33
@@ -40,45 +40,45 @@ public class Saml2X509CredentialTests {
|
||||
public ExpectedException exception = ExpectedException.none();
|
||||
|
||||
private Saml2X509Credential credential;
|
||||
|
||||
private PrivateKey key;
|
||||
|
||||
private X509Certificate certificate;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
String keyData = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n" +
|
||||
"VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n" +
|
||||
"cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n" +
|
||||
"Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n" +
|
||||
"x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n" +
|
||||
"wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n" +
|
||||
"vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n" +
|
||||
"8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n" +
|
||||
"oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n" +
|
||||
"EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n" +
|
||||
"KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n" +
|
||||
"YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n" +
|
||||
"9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" +
|
||||
"INrtuLp4YHbgk1mi\n" +
|
||||
"-----END PRIVATE KEY-----";
|
||||
String keyData = "-----BEGIN PRIVATE KEY-----\n"
|
||||
+ "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n"
|
||||
+ "VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n"
|
||||
+ "cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n"
|
||||
+ "Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n"
|
||||
+ "x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n"
|
||||
+ "wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n"
|
||||
+ "vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n"
|
||||
+ "8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n"
|
||||
+ "oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n"
|
||||
+ "EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n"
|
||||
+ "KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n"
|
||||
+ "YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n"
|
||||
+ "9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" + "INrtuLp4YHbgk1mi\n"
|
||||
+ "-----END PRIVATE KEY-----";
|
||||
key = RsaKeyConverters.pkcs8().convert(new ByteArrayInputStream(keyData.getBytes(UTF_8)));
|
||||
final CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
String certificateData = "-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n" +
|
||||
"VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n" +
|
||||
"A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n" +
|
||||
"DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n" +
|
||||
"MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n" +
|
||||
"MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n" +
|
||||
"TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n" +
|
||||
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n" +
|
||||
"vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n" +
|
||||
"+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n" +
|
||||
"y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n" +
|
||||
"XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n" +
|
||||
"qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n" +
|
||||
"RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
String certificateData = "-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n"
|
||||
+ "VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n"
|
||||
+ "A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n"
|
||||
+ "DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n"
|
||||
+ "MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n"
|
||||
+ "MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n"
|
||||
+ "TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n"
|
||||
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n"
|
||||
+ "vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n"
|
||||
+ "+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n"
|
||||
+ "y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n"
|
||||
+ "XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n"
|
||||
+ "qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n"
|
||||
+ "RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" + "-----END CERTIFICATE-----";
|
||||
certificate = (X509Certificate) factory
|
||||
.generateCertificate(new ByteArrayInputStream(certificateData.getBytes(UTF_8)));
|
||||
}
|
||||
@@ -145,5 +145,4 @@ public class Saml2X509CredentialTests {
|
||||
new Saml2X509Credential(certificate, DECRYPTION);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+83
-88
@@ -34,6 +34,7 @@ import static org.springframework.security.saml2.credentials.Saml2X509Credential
|
||||
import static org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION;
|
||||
|
||||
public final class TestSaml2X509Credentials {
|
||||
|
||||
public static Saml2X509Credential assertingPartySigningCredential() {
|
||||
return new Saml2X509Credential(idpPrivateKey(), idpCertificate(), SIGNING);
|
||||
}
|
||||
@@ -61,9 +62,7 @@ public final class TestSaml2X509Credentials {
|
||||
private static X509Certificate certificate(String cert) {
|
||||
ByteArrayInputStream certBytes = new ByteArrayInputStream(cert.getBytes());
|
||||
try {
|
||||
return (X509Certificate) CertificateFactory
|
||||
.getInstance("X.509")
|
||||
.generateCertificate(certBytes);
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certBytes);
|
||||
}
|
||||
catch (CertificateException e) {
|
||||
throw new Saml2Exception(e);
|
||||
@@ -79,101 +78,97 @@ public final class TestSaml2X509Credentials {
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate idpCertificate() {
|
||||
return certificate("-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD\n"
|
||||
+ "VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD\n"
|
||||
+ "VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX\n"
|
||||
+ "c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw\n"
|
||||
+ "aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ\n"
|
||||
+ "BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa\n"
|
||||
+ "BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD\n"
|
||||
+ "DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr\n"
|
||||
+ "QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62\n"
|
||||
+ "E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz\n"
|
||||
+ "2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW\n"
|
||||
+ "RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ\n"
|
||||
+ "nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5\n"
|
||||
+ "cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph\n"
|
||||
+ "iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5\n"
|
||||
+ "ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD\n"
|
||||
+ "AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO\n"
|
||||
+ "nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v\n"
|
||||
+ "ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu\n"
|
||||
+ "xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z\n"
|
||||
+ "V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3\n"
|
||||
+ "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n"
|
||||
+ "-----END CERTIFICATE-----\n");
|
||||
private static X509Certificate idpCertificate() {
|
||||
return certificate(
|
||||
"-----BEGIN CERTIFICATE-----\n" + "MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD\n"
|
||||
+ "VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD\n"
|
||||
+ "VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX\n"
|
||||
+ "c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw\n"
|
||||
+ "aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ\n"
|
||||
+ "BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa\n"
|
||||
+ "BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD\n"
|
||||
+ "DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr\n"
|
||||
+ "QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62\n"
|
||||
+ "E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz\n"
|
||||
+ "2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW\n"
|
||||
+ "RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ\n"
|
||||
+ "nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5\n"
|
||||
+ "cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph\n"
|
||||
+ "iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5\n"
|
||||
+ "ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD\n"
|
||||
+ "AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO\n"
|
||||
+ "nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v\n"
|
||||
+ "ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu\n"
|
||||
+ "xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z\n"
|
||||
+ "V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3\n"
|
||||
+ "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n" + "-----END CERTIFICATE-----\n");
|
||||
}
|
||||
|
||||
|
||||
private static PrivateKey idpPrivateKey() {
|
||||
return privateKey("-----BEGIN PRIVATE KEY-----\n"
|
||||
+ "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4cn62E1xLqpN3\n"
|
||||
+ "4PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZX\n"
|
||||
+ "W+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHE\n"
|
||||
+ "fDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7h\n"
|
||||
+ "Z6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/T\n"
|
||||
+ "Xy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7\n"
|
||||
+ "I+J5lS8VAgMBAAECggEBAKyxBlIS7mcp3chvq0RF7B3PHFJMMzkwE+t3pLJcs4cZ\n"
|
||||
+ "nezh/KbREfP70QjXzk/llnZCvxeIs5vRu24vbdBm79qLHqBuHp8XfHHtuo2AfoAQ\n"
|
||||
+ "l4h047Xc/+TKMivnPQ0jX9qqndKDLqZDf5wnbslDmlskvF0a/MjsLU0TxtOfo+dB\n"
|
||||
+ "t55FW11cGqxZwhS5Gnr+cbw3OkHz23b9gEOt9qfwPVepeysbmm9FjU+k4yVa7rAN\n"
|
||||
+ "xcbzVb6Y7GCITe2tgvvEHmjB9BLmWrH3mZ3Af17YU/iN6TrpPd6Sj3QoS+2wGtAe\n"
|
||||
+ "HbUs3CKJu7bIHcj4poal6Kh8519S+erJTtqQ8M0ZiEECgYEA43hLYAPaUueFkdfh\n"
|
||||
+ "9K/7ClH6436CUH3VdizwUXi26fdhhV/I/ot6zLfU2mgEHU22LBECWQGtAFm8kv0P\n"
|
||||
+ "zPn+qjaR3e62l5PIlSYbnkIidzoDZ2ztu4jF5LgStlTJQPteFEGgZVl5o9DaSZOq\n"
|
||||
+ "Yd7G3XqXuQ1VGMW58G5FYJPtA1cCgYEAz5TPUtK+R2KXHMjUwlGY9AefQYRYmyX2\n"
|
||||
+ "Tn/OFgKvY8lpAkMrhPKONq7SMYc8E9v9G7A0dIOXvW7QOYSapNhKU+np3lUafR5F\n"
|
||||
+ "4ZN0bxZ9qjHbn3AMYeraKjeutHvlLtbHdIc1j3sxe/EzltRsYmiqLdEBW0p6hwWg\n"
|
||||
+ "tyGhYWVyaXMCgYAfDOKtHpmEy5nOCLwNXKBWDk7DExfSyPqEgSnk1SeS1HP5ctPK\n"
|
||||
+ "+1st6sIhdiVpopwFc+TwJWxqKdW18tlfT5jVv1E2DEnccw3kXilS9xAhWkfwrEvf\n"
|
||||
+ "V5I74GydewFl32o+NZ8hdo9GL1I8zO1rIq/et8dSOWGuWf9BtKu/vTGTTQKBgFxU\n"
|
||||
+ "VjsCnbvmsEwPUAL2hE/WrBFaKocnxXx5AFNt8lEyHtDwy4Sg1nygGcIJ4sD6koQk\n"
|
||||
+ "RdClT3LkvR04TAiSY80bN/i6ZcPNGUwSaDGZEWAIOSWbkwZijZNFnSGOEgxZX/IG\n"
|
||||
+ "yd39766vREEMTwEeiMNEOZQ/dmxkJm4OOVe25cLdAoGACOtPnq1Fxay80UYBf4rQ\n"
|
||||
+ "+bJ9yX1ulB8WIree1hD7OHSB2lRHxrVYWrglrTvkh63Lgx+EcsTV788OsvAVfPPz\n"
|
||||
+ "BZrn8SdDlQqalMxUBYEFwnsYD3cQ8yOUnijFVC4xNcdDv8OIqVgSk4KKxU5AshaA\n" + "xk6Mox+u8Cc2eAK12H13i+8=\n"
|
||||
+ "-----END PRIVATE KEY-----\n");
|
||||
return privateKey(
|
||||
"-----BEGIN PRIVATE KEY-----\n" + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4cn62E1xLqpN3\n"
|
||||
+ "4PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZX\n"
|
||||
+ "W+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHE\n"
|
||||
+ "fDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7h\n"
|
||||
+ "Z6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/T\n"
|
||||
+ "Xy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7\n"
|
||||
+ "I+J5lS8VAgMBAAECggEBAKyxBlIS7mcp3chvq0RF7B3PHFJMMzkwE+t3pLJcs4cZ\n"
|
||||
+ "nezh/KbREfP70QjXzk/llnZCvxeIs5vRu24vbdBm79qLHqBuHp8XfHHtuo2AfoAQ\n"
|
||||
+ "l4h047Xc/+TKMivnPQ0jX9qqndKDLqZDf5wnbslDmlskvF0a/MjsLU0TxtOfo+dB\n"
|
||||
+ "t55FW11cGqxZwhS5Gnr+cbw3OkHz23b9gEOt9qfwPVepeysbmm9FjU+k4yVa7rAN\n"
|
||||
+ "xcbzVb6Y7GCITe2tgvvEHmjB9BLmWrH3mZ3Af17YU/iN6TrpPd6Sj3QoS+2wGtAe\n"
|
||||
+ "HbUs3CKJu7bIHcj4poal6Kh8519S+erJTtqQ8M0ZiEECgYEA43hLYAPaUueFkdfh\n"
|
||||
+ "9K/7ClH6436CUH3VdizwUXi26fdhhV/I/ot6zLfU2mgEHU22LBECWQGtAFm8kv0P\n"
|
||||
+ "zPn+qjaR3e62l5PIlSYbnkIidzoDZ2ztu4jF5LgStlTJQPteFEGgZVl5o9DaSZOq\n"
|
||||
+ "Yd7G3XqXuQ1VGMW58G5FYJPtA1cCgYEAz5TPUtK+R2KXHMjUwlGY9AefQYRYmyX2\n"
|
||||
+ "Tn/OFgKvY8lpAkMrhPKONq7SMYc8E9v9G7A0dIOXvW7QOYSapNhKU+np3lUafR5F\n"
|
||||
+ "4ZN0bxZ9qjHbn3AMYeraKjeutHvlLtbHdIc1j3sxe/EzltRsYmiqLdEBW0p6hwWg\n"
|
||||
+ "tyGhYWVyaXMCgYAfDOKtHpmEy5nOCLwNXKBWDk7DExfSyPqEgSnk1SeS1HP5ctPK\n"
|
||||
+ "+1st6sIhdiVpopwFc+TwJWxqKdW18tlfT5jVv1E2DEnccw3kXilS9xAhWkfwrEvf\n"
|
||||
+ "V5I74GydewFl32o+NZ8hdo9GL1I8zO1rIq/et8dSOWGuWf9BtKu/vTGTTQKBgFxU\n"
|
||||
+ "VjsCnbvmsEwPUAL2hE/WrBFaKocnxXx5AFNt8lEyHtDwy4Sg1nygGcIJ4sD6koQk\n"
|
||||
+ "RdClT3LkvR04TAiSY80bN/i6ZcPNGUwSaDGZEWAIOSWbkwZijZNFnSGOEgxZX/IG\n"
|
||||
+ "yd39766vREEMTwEeiMNEOZQ/dmxkJm4OOVe25cLdAoGACOtPnq1Fxay80UYBf4rQ\n"
|
||||
+ "+bJ9yX1ulB8WIree1hD7OHSB2lRHxrVYWrglrTvkh63Lgx+EcsTV788OsvAVfPPz\n"
|
||||
+ "BZrn8SdDlQqalMxUBYEFwnsYD3cQ8yOUnijFVC4xNcdDv8OIqVgSk4KKxU5AshaA\n"
|
||||
+ "xk6Mox+u8Cc2eAK12H13i+8=\n" + "-----END PRIVATE KEY-----\n");
|
||||
}
|
||||
|
||||
private static X509Certificate spCertificate() {
|
||||
|
||||
return certificate("-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n" +
|
||||
"VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n" +
|
||||
"A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n" +
|
||||
"DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n" +
|
||||
"MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n" +
|
||||
"MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n" +
|
||||
"TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n" +
|
||||
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n" +
|
||||
"vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n" +
|
||||
"+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n" +
|
||||
"y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n" +
|
||||
"XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n" +
|
||||
"qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n" +
|
||||
"RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" +
|
||||
"-----END CERTIFICATE-----");
|
||||
return certificate(
|
||||
"-----BEGIN CERTIFICATE-----\n" + "MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n"
|
||||
+ "VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n"
|
||||
+ "A1UECgwUU3ByaW5nIFNlY3VyaXR5IFNBTUwxCzAJBgNVBAsMAnNwMSAwHgYDVQQD\n"
|
||||
+ "DBdzcC5zcHJpbmcuc2VjdXJpdHkuc2FtbDAeFw0xODA1MTQxNDMwNDRaFw0yODA1\n"
|
||||
+ "MTExNDMwNDRaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjES\n"
|
||||
+ "MBAGA1UEBwwJVmFuY291dmVyMR0wGwYDVQQKDBRTcHJpbmcgU2VjdXJpdHkgU0FN\n"
|
||||
+ "TDELMAkGA1UECwwCc3AxIDAeBgNVBAMMF3NwLnNwcmluZy5zZWN1cml0eS5zYW1s\n"
|
||||
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRu7/EI0BlNzMEBFVAcbx+lLos\n"
|
||||
+ "vzIWU+01dGTY8gBdhMQNYKZ92lMceo2CuVJ66cUURPym3i7nGGzoSnAxAre+0YIM\n"
|
||||
+ "+U0razrWtAUE735bkcqELZkOTZLelaoOztmWqRbe5OuEmpewH7cx+kNgcVjdctOG\n"
|
||||
+ "y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n"
|
||||
+ "XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n"
|
||||
+ "qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n"
|
||||
+ "RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" + "-----END CERTIFICATE-----");
|
||||
}
|
||||
|
||||
private static PrivateKey spPrivateKey() {
|
||||
return privateKey("-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n" +
|
||||
"VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n" +
|
||||
"cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n" +
|
||||
"Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n" +
|
||||
"x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n" +
|
||||
"wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n" +
|
||||
"vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n" +
|
||||
"8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n" +
|
||||
"oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n" +
|
||||
"EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n" +
|
||||
"KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n" +
|
||||
"YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n" +
|
||||
"9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" +
|
||||
"INrtuLp4YHbgk1mi\n" +
|
||||
"-----END PRIVATE KEY-----");
|
||||
return privateKey(
|
||||
"-----BEGIN PRIVATE KEY-----\n" + "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n"
|
||||
+ "VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n"
|
||||
+ "cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\n"
|
||||
+ "Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\n"
|
||||
+ "x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\n"
|
||||
+ "wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\n"
|
||||
+ "vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n"
|
||||
+ "8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\n"
|
||||
+ "oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\n"
|
||||
+ "EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n"
|
||||
+ "KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n"
|
||||
+ "YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n"
|
||||
+ "9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" + "INrtuLp4YHbgk1mi\n"
|
||||
+ "-----END PRIVATE KEY-----");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-4
@@ -44,15 +44,13 @@ public class DefaultSaml2AuthenticatedPrincipalTests {
|
||||
Map<String, List<Object>> attributes = new LinkedHashMap<>();
|
||||
attributes.put("email", Arrays.asList("john.doe@example.com", "doe.john@example.com"));
|
||||
assertThatCode(() -> new DefaultSaml2AuthenticatedPrincipal(null, attributes))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("name cannot be null");
|
||||
.isInstanceOf(IllegalArgumentException.class).hasMessageContaining("name cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createDefaultSaml2AuthenticatedPrincipalWhenAttributesNullThenException() {
|
||||
assertThatCode(() -> new DefaultSaml2AuthenticatedPrincipal("user", null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("attributes cannot be null");
|
||||
.isInstanceOf(IllegalArgumentException.class).hasMessageContaining("attributes cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -87,4 +85,5 @@ public class DefaultSaml2AuthenticatedPrincipalTests {
|
||||
assertThat((Boolean) registrationInfo.get(0)).isEqualTo(registered);
|
||||
assertThat((Instant) registrationInfo.get(1)).isEqualTo(registeredDate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+35
-36
@@ -97,7 +97,9 @@ import static org.springframework.util.StringUtils.hasText;
|
||||
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();
|
||||
@@ -109,7 +111,8 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
public void supportsWhenSaml2AuthenticationTokenThenReturnTrue() {
|
||||
|
||||
assertThat(this.provider.supports(Saml2AuthenticationToken.class))
|
||||
.withFailMessage(OpenSamlAuthenticationProvider.class + "should support " + Saml2AuthenticationToken.class)
|
||||
.withFailMessage(
|
||||
OpenSamlAuthenticationProvider.class + "should support " + Saml2AuthenticationToken.class)
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@@ -151,8 +154,7 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
@Test
|
||||
public void authenticateWhenNoAssertionsPresentThenThrowAuthenticationException() {
|
||||
this.exception.expect(
|
||||
authenticationMatcher(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, "No assertions found in response.")
|
||||
);
|
||||
authenticationMatcher(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, "No assertions found in response."));
|
||||
|
||||
Saml2AuthenticationToken token = token(response(), assertingPartySigningCredential());
|
||||
this.provider.authenticate(token);
|
||||
@@ -174,11 +176,7 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
|
||||
Response response = response();
|
||||
Assertion assertion = assertion();
|
||||
assertion
|
||||
.getSubject()
|
||||
.getSubjectConfirmations()
|
||||
.get(0)
|
||||
.getSubjectConfirmationData()
|
||||
assertion.getSubject().getSubjectConfirmations().get(0).getSubjectConfirmationData()
|
||||
.setNotOnOrAfter(DateTime.now().minus(Duration.standardDays(3)));
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
response.getAssertions().add(assertion);
|
||||
@@ -187,7 +185,7 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticateWhenMissingSubjectThenThrowAuthenticationException() {
|
||||
public void authenticateWhenMissingSubjectThenThrowAuthenticationException() {
|
||||
this.exception.expect(authenticationMatcher(Saml2ErrorCodes.SUBJECT_NOT_FOUND));
|
||||
|
||||
Response response = response();
|
||||
@@ -205,10 +203,7 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
|
||||
Response response = response();
|
||||
Assertion assertion = assertion();
|
||||
assertion
|
||||
.getSubject()
|
||||
.getNameID()
|
||||
.setValue(null);
|
||||
assertion.getSubject().getNameID().setValue(null);
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
response.getAssertions().add(assertion);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential());
|
||||
@@ -219,9 +214,8 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
public void authenticateWhenAssertionContainsValidationAddressThenItSucceeds() throws Exception {
|
||||
Response response = response();
|
||||
Assertion assertion = assertion();
|
||||
assertion.getSubject().getSubjectConfirmations().forEach(
|
||||
sc -> sc.getSubjectConfirmationData().setAddress("10.10.10.10")
|
||||
);
|
||||
assertion.getSubject().getSubjectConfirmations()
|
||||
.forEach(sc -> sc.getSubjectConfirmationData().setAddress("10.10.10.10"));
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
response.getAssertions().add(assertion);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential());
|
||||
@@ -268,11 +262,14 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
when(marshaller.marshall(any(XMLObject.class))).thenReturn(attributeElement);
|
||||
|
||||
try {
|
||||
XMLObjectProviderRegistrySupport.getMarshallerFactory().registerMarshaller(AttributeValue.DEFAULT_ELEMENT_NAME, marshaller);
|
||||
XMLObjectProviderRegistrySupport.getMarshallerFactory()
|
||||
.registerMarshaller(AttributeValue.DEFAULT_ELEMENT_NAME, marshaller);
|
||||
this.provider.authenticate(token);
|
||||
verify(marshaller, atLeastOnce()).marshall(any(XMLObject.class));
|
||||
} finally {
|
||||
XMLObjectProviderRegistrySupport.getMarshallerFactory().deregisterMarshaller(AttributeValue.DEFAULT_ELEMENT_NAME);
|
||||
}
|
||||
finally {
|
||||
XMLObjectProviderRegistrySupport.getMarshallerFactory()
|
||||
.deregisterMarshaller(AttributeValue.DEFAULT_ELEMENT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +290,8 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
Assertion assertion = signed(assertion(), assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion, assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(), relyingPartyDecryptingCredential());
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(),
|
||||
relyingPartyDecryptingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@@ -303,7 +301,8 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion(), assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
signed(response, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(), relyingPartyDecryptingCredential());
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(),
|
||||
relyingPartyDecryptingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
@@ -317,16 +316,15 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
assertion.getSubject().setEncryptedID(encryptedID);
|
||||
response.getAssertions().add(assertion);
|
||||
signed(assertion, assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(), relyingPartyDecryptingCredential());
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(),
|
||||
relyingPartyDecryptingCredential());
|
||||
this.provider.authenticate(token);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void authenticateWhenDecryptionKeysAreMissingThenThrowAuthenticationException() throws Exception {
|
||||
this.exception.expect(
|
||||
authenticationMatcher(Saml2ErrorCodes.DECRYPTION_ERROR, "Failed to decrypt EncryptedData")
|
||||
);
|
||||
this.exception
|
||||
.expect(authenticationMatcher(Saml2ErrorCodes.DECRYPTION_ERROR, "Failed to decrypt EncryptedData"));
|
||||
|
||||
Response response = response();
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion(), assertingPartyEncryptingCredential());
|
||||
@@ -337,9 +335,8 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
|
||||
@Test
|
||||
public void authenticateWhenDecryptionKeysAreWrongThenThrowAuthenticationException() throws Exception {
|
||||
this.exception.expect(
|
||||
authenticationMatcher(Saml2ErrorCodes.DECRYPTION_ERROR, "Failed to decrypt EncryptedData")
|
||||
);
|
||||
this.exception
|
||||
.expect(authenticationMatcher(Saml2ErrorCodes.DECRYPTION_ERROR, "Failed to decrypt EncryptedData"));
|
||||
|
||||
Response response = response();
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion(), assertingPartyEncryptingCredential());
|
||||
@@ -354,7 +351,8 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
Assertion assertion = signed(assertion(), assertingPartySigningCredential(), RELYING_PARTY_ENTITY_ID);
|
||||
EncryptedAssertion encryptedAssertion = encrypted(assertion, assertingPartyEncryptingCredential());
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(), relyingPartyDecryptingCredential());
|
||||
Saml2AuthenticationToken token = token(response, relyingPartyVerifyingCredential(),
|
||||
relyingPartyDecryptingCredential());
|
||||
Saml2Authentication authentication = (Saml2Authentication) this.provider.authenticate(token);
|
||||
|
||||
// the following code will throw an exception if authentication isn't serializable
|
||||
@@ -409,8 +407,7 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
|
||||
@Test
|
||||
public void setConditionValidatorsWhenNullOrEmptyThenIllegalArgument() {
|
||||
assertThatCode(() -> this.provider.setConditionValidators(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> this.provider.setConditionValidators(null)).isInstanceOf(IllegalArgumentException.class);
|
||||
|
||||
assertThatCode(() -> this.provider.setConditionValidators(Collections.emptyList()))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
@@ -425,7 +422,8 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
Marshaller marshaller = getMarshallerFactory().getMarshaller(object);
|
||||
Element element = marshaller.marshall(object);
|
||||
return SerializeSupport.nodeToString(element);
|
||||
} catch (MarshallingException e) {
|
||||
}
|
||||
catch (MarshallingException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
@@ -455,7 +453,7 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
|
||||
@Override
|
||||
public void describeTo(Description desc) {
|
||||
String excepting = "Saml2AuthenticationException[code="+code+"; description="+description+"]";
|
||||
String excepting = "Saml2AuthenticationException[code=" + code + "; description=" + description + "]";
|
||||
desc.appendText(excepting);
|
||||
|
||||
}
|
||||
@@ -468,8 +466,8 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
}
|
||||
|
||||
private Saml2AuthenticationToken token(String payload, Saml2X509Credential... credentials) {
|
||||
return new Saml2AuthenticationToken(payload,
|
||||
DESTINATION, ASSERTING_PARTY_ENTITY_ID, RELYING_PARTY_ENTITY_ID, Arrays.asList(credentials));
|
||||
return new Saml2AuthenticationToken(payload, DESTINATION, ASSERTING_PARTY_ENTITY_ID, RELYING_PARTY_ENTITY_ID,
|
||||
Arrays.asList(credentials));
|
||||
}
|
||||
|
||||
private static Element element(String xml) throws Exception {
|
||||
@@ -478,4 +476,5 @@ public class OpenSamlAuthenticationProviderTests {
|
||||
Document doc = builder.parse(new InputSource(new StringReader(xml)));
|
||||
return doc.getDocumentElement();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
-51
@@ -57,10 +57,13 @@ import static org.springframework.security.saml2.provider.service.registration.S
|
||||
public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
|
||||
private OpenSamlAuthenticationRequestFactory factory;
|
||||
|
||||
private Saml2AuthenticationRequestContext.Builder contextBuilder;
|
||||
|
||||
private Saml2AuthenticationRequestContext context;
|
||||
|
||||
private RelyingPartyRegistration.Builder relyingPartyRegistrationBuilder;
|
||||
|
||||
private RelyingPartyRegistration relyingPartyRegistration;
|
||||
|
||||
private AuthnRequestUnmarshaller unmarshaller = (AuthnRequestUnmarshaller) getUnmarshallerFactory()
|
||||
@@ -74,30 +77,27 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
this.relyingPartyRegistrationBuilder = RelyingPartyRegistration.withRegistrationId("id")
|
||||
.assertionConsumerServiceLocation("template")
|
||||
.providerDetails(c -> c.webSsoUrl("https://destination/sso"))
|
||||
.providerDetails(c -> c.entityId("remote-entity-id"))
|
||||
.localEntityIdTemplate("local-entity-id")
|
||||
.providerDetails(c -> c.entityId("remote-entity-id")).localEntityIdTemplate("local-entity-id")
|
||||
.credentials(c -> c.add(relyingPartySigningCredential()));
|
||||
this.relyingPartyRegistration = this.relyingPartyRegistrationBuilder.build();
|
||||
contextBuilder = Saml2AuthenticationRequestContext.builder()
|
||||
.issuer("https://issuer")
|
||||
.relyingPartyRegistration(relyingPartyRegistration)
|
||||
.assertionConsumerServiceUrl("https://issuer/sso");
|
||||
contextBuilder = Saml2AuthenticationRequestContext.builder().issuer("https://issuer")
|
||||
.relyingPartyRegistration(relyingPartyRegistration).assertionConsumerServiceUrl("https://issuer/sso");
|
||||
context = contextBuilder.build();
|
||||
factory = new OpenSamlAuthenticationRequestFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAuthenticationRequestWhenInvokingDeprecatedMethodThenReturnsXML() {
|
||||
Saml2AuthenticationRequest request = Saml2AuthenticationRequest.withAuthenticationRequestContext(context).build();
|
||||
Saml2AuthenticationRequest request = Saml2AuthenticationRequest.withAuthenticationRequestContext(context)
|
||||
.build();
|
||||
String result = factory.createAuthenticationRequest(request);
|
||||
assertThat(result.replace("\n", "")).startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\"?><saml2p:AuthnRequest");
|
||||
assertThat(result.replace("\n", ""))
|
||||
.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\"?><saml2p:AuthnRequest");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createRedirectAuthenticationRequestWhenUsingContextThenAllValuesAreSet() {
|
||||
context = contextBuilder
|
||||
.relayState("Relay State Value")
|
||||
.build();
|
||||
context = contextBuilder.relayState("Relay State Value").build();
|
||||
Saml2RedirectAuthenticationRequest result = factory.createRedirectAuthenticationRequest(context);
|
||||
assertThat(result.getSamlRequest()).isNotEmpty();
|
||||
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
|
||||
@@ -109,13 +109,9 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
@Test
|
||||
public void createRedirectAuthenticationRequestWhenNotSignRequestThenNoSignatureIsPresent() {
|
||||
|
||||
context = contextBuilder
|
||||
.relayState("Relay State Value")
|
||||
.relyingPartyRegistration(
|
||||
withRelyingPartyRegistration(relyingPartyRegistration)
|
||||
.providerDetails(c -> c.signAuthNRequest(false))
|
||||
.build()
|
||||
)
|
||||
context = contextBuilder.relayState("Relay State Value")
|
||||
.relyingPartyRegistration(withRelyingPartyRegistration(relyingPartyRegistration)
|
||||
.providerDetails(c -> c.signAuthNRequest(false)).build())
|
||||
.build();
|
||||
Saml2RedirectAuthenticationRequest result = factory.createRedirectAuthenticationRequest(context);
|
||||
assertThat(result.getSamlRequest()).isNotEmpty();
|
||||
@@ -127,37 +123,26 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
|
||||
@Test
|
||||
public void createPostAuthenticationRequestWhenNotSignRequestThenNoSignatureIsPresent() {
|
||||
context = contextBuilder
|
||||
.relayState("Relay State Value")
|
||||
.relyingPartyRegistration(
|
||||
withRelyingPartyRegistration(relyingPartyRegistration)
|
||||
.providerDetails(c -> c.signAuthNRequest(false))
|
||||
.build()
|
||||
)
|
||||
context = contextBuilder.relayState("Relay State Value")
|
||||
.relyingPartyRegistration(withRelyingPartyRegistration(relyingPartyRegistration)
|
||||
.providerDetails(c -> c.signAuthNRequest(false)).build())
|
||||
.build();
|
||||
Saml2PostAuthenticationRequest result = factory.createPostAuthenticationRequest(context);
|
||||
assertThat(result.getSamlRequest()).isNotEmpty();
|
||||
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
|
||||
assertThat(result.getBinding()).isEqualTo(POST);
|
||||
assertThat(new String(samlDecode(result.getSamlRequest()), UTF_8))
|
||||
.doesNotContain("ds:Signature");
|
||||
assertThat(new String(samlDecode(result.getSamlRequest()), UTF_8)).doesNotContain("ds:Signature");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createPostAuthenticationRequestWhenSignRequestThenSignatureIsPresent() {
|
||||
context = contextBuilder
|
||||
.relayState("Relay State Value")
|
||||
.relyingPartyRegistration(
|
||||
withRelyingPartyRegistration(relyingPartyRegistration)
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
context = contextBuilder.relayState("Relay State Value")
|
||||
.relyingPartyRegistration(withRelyingPartyRegistration(relyingPartyRegistration).build()).build();
|
||||
Saml2PostAuthenticationRequest result = factory.createPostAuthenticationRequest(context);
|
||||
assertThat(result.getSamlRequest()).isNotEmpty();
|
||||
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
|
||||
assertThat(result.getBinding()).isEqualTo(POST);
|
||||
assertThat(new String(samlDecode(result.getSamlRequest()), UTF_8))
|
||||
.contains("ds:Signature");
|
||||
assertThat(new String(samlDecode(result.getSamlRequest()), UTF_8)).contains("ds:Signature");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -182,9 +167,10 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
|
||||
@Test
|
||||
public void createPostAuthenticationRequestWhenAuthnRequestConsumerThenUses() {
|
||||
Function<Saml2AuthenticationRequestContext, Consumer<AuthnRequest>> authnRequestConsumerResolver =
|
||||
mock(Function.class);
|
||||
when(authnRequestConsumerResolver.apply(this.context)).thenReturn(authnRequest -> {});
|
||||
Function<Saml2AuthenticationRequestContext, Consumer<AuthnRequest>> authnRequestConsumerResolver = mock(
|
||||
Function.class);
|
||||
when(authnRequestConsumerResolver.apply(this.context)).thenReturn(authnRequest -> {
|
||||
});
|
||||
this.factory.setAuthnRequestConsumerResolver(authnRequestConsumerResolver);
|
||||
|
||||
this.factory.createPostAuthenticationRequest(this.context);
|
||||
@@ -193,9 +179,10 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
|
||||
@Test
|
||||
public void createRedirectAuthenticationRequestWhenAuthnRequestConsumerThenUses() {
|
||||
Function<Saml2AuthenticationRequestContext, Consumer<AuthnRequest>> authnRequestConsumerResolver =
|
||||
mock(Function.class);
|
||||
when(authnRequestConsumerResolver.apply(this.context)).thenReturn(authnRequest -> {});
|
||||
Function<Saml2AuthenticationRequestContext, Consumer<AuthnRequest>> authnRequestConsumerResolver = mock(
|
||||
Function.class);
|
||||
when(authnRequestConsumerResolver.apply(this.context)).thenReturn(authnRequest -> {
|
||||
});
|
||||
this.factory.setAuthnRequestConsumerResolver(authnRequestConsumerResolver);
|
||||
|
||||
this.factory.createRedirectAuthenticationRequest(this.context);
|
||||
@@ -211,11 +198,9 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
@Test
|
||||
public void createPostAuthenticationRequestWhenAssertionConsumerServiceBindingThenUses() {
|
||||
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationBuilder
|
||||
.assertionConsumerServiceBinding(REDIRECT)
|
||||
.build();
|
||||
.assertionConsumerServiceBinding(REDIRECT).build();
|
||||
Saml2AuthenticationRequestContext context = this.contextBuilder
|
||||
.relyingPartyRegistration(relyingPartyRegistration)
|
||||
.build();
|
||||
.relyingPartyRegistration(relyingPartyRegistration).build();
|
||||
Saml2PostAuthenticationRequest request = this.factory.createPostAuthenticationRequest(context);
|
||||
String samlRequest = request.getSamlRequest();
|
||||
String inflated = new String(samlDecode(samlRequest));
|
||||
@@ -223,9 +208,9 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
}
|
||||
|
||||
private AuthnRequest getAuthNRequest(Saml2MessageBinding binding) {
|
||||
AbstractSaml2AuthenticationRequest result = (binding == REDIRECT) ?
|
||||
factory.createRedirectAuthenticationRequest(context) :
|
||||
factory.createPostAuthenticationRequest(context);
|
||||
AbstractSaml2AuthenticationRequest result = (binding == REDIRECT)
|
||||
? factory.createRedirectAuthenticationRequest(context)
|
||||
: factory.createPostAuthenticationRequest(context);
|
||||
String samlRequest = result.getSamlRequest();
|
||||
assertThat(samlRequest).isNotEmpty();
|
||||
if (result.getBinding() == REDIRECT) {
|
||||
@@ -235,8 +220,7 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
samlRequest = new String(samlDecode(samlRequest), UTF_8);
|
||||
}
|
||||
try {
|
||||
Document document = getParserPool().parse(
|
||||
new ByteArrayInputStream(samlRequest.getBytes(UTF_8)));
|
||||
Document document = getParserPool().parse(new ByteArrayInputStream(samlRequest.getBytes(UTF_8)));
|
||||
Element element = document.getDocumentElement();
|
||||
return (AuthnRequest) this.unmarshaller.unmarshall(element);
|
||||
}
|
||||
@@ -244,4 +228,5 @@ public class OpenSamlAuthenticationRequestFactoryTests {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-14
@@ -35,20 +35,16 @@ public class Saml2AuthenticationRequestFactoryTests {
|
||||
private RelyingPartyRegistration registration = RelyingPartyRegistration.withRegistrationId("id")
|
||||
.assertionConsumerServiceUrlTemplate("template")
|
||||
.providerDetails(c -> c.webSsoUrl("https://example.com/destination"))
|
||||
.providerDetails(c -> c.entityId("remote-entity-id"))
|
||||
.localEntityIdTemplate("local-entity-id")
|
||||
.credentials(c -> c.add(relyingPartySigningCredential()))
|
||||
.build();
|
||||
.providerDetails(c -> c.entityId("remote-entity-id")).localEntityIdTemplate("local-entity-id")
|
||||
.credentials(c -> c.add(relyingPartySigningCredential())).build();
|
||||
|
||||
@Test
|
||||
public void createAuthenticationRequestParametersWhenRedirectDefaultIsUsedMessageIsDeflatedAndEncoded() {
|
||||
final String value = "Test String: "+ UUID.randomUUID().toString();
|
||||
final String value = "Test String: " + UUID.randomUUID().toString();
|
||||
Saml2AuthenticationRequestFactory factory = request -> value;
|
||||
Saml2AuthenticationRequestContext request = Saml2AuthenticationRequestContext.builder()
|
||||
.relyingPartyRegistration(registration)
|
||||
.issuer("https://example.com/issuer")
|
||||
.assertionConsumerServiceUrl("https://example.com/acs-url")
|
||||
.build();
|
||||
.relyingPartyRegistration(registration).issuer("https://example.com/issuer")
|
||||
.assertionConsumerServiceUrl("https://example.com/acs-url").build();
|
||||
Saml2RedirectAuthenticationRequest response = factory.createRedirectAuthenticationRequest(request);
|
||||
String resultValue = response.getSamlRequest();
|
||||
byte[] decoded = samlDecode(resultValue);
|
||||
@@ -58,16 +54,15 @@ public class Saml2AuthenticationRequestFactoryTests {
|
||||
|
||||
@Test
|
||||
public void createAuthenticationRequestParametersWhenPostDefaultIsUsedMessageIsEncoded() {
|
||||
final String value = "Test String: "+ UUID.randomUUID().toString();
|
||||
final String value = "Test String: " + UUID.randomUUID().toString();
|
||||
Saml2AuthenticationRequestFactory factory = request -> value;
|
||||
Saml2AuthenticationRequestContext request = Saml2AuthenticationRequestContext.builder()
|
||||
.relyingPartyRegistration(registration)
|
||||
.issuer("https://example.com/issuer")
|
||||
.assertionConsumerServiceUrl("https://example.com/acs-url")
|
||||
.build();
|
||||
.relyingPartyRegistration(registration).issuer("https://example.com/issuer")
|
||||
.assertionConsumerServiceUrl("https://example.com/acs-url").build();
|
||||
Saml2PostAuthenticationRequest response = factory.createPostAuthenticationRequest(request);
|
||||
String resultValue = response.getSamlRequest();
|
||||
byte[] decoded = samlDecode(resultValue);
|
||||
assertThat(new String(decoded)).isEqualTo(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+32
-28
@@ -21,6 +21,7 @@ import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.xml.namespace.QName;
|
||||
@@ -81,16 +82,21 @@ import org.springframework.security.saml2.core.Saml2X509Credential;
|
||||
import static org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport.getBuilderFactory;
|
||||
|
||||
final class TestOpenSamlObjects {
|
||||
|
||||
static {
|
||||
OpenSamlInitializationService.initialize();
|
||||
}
|
||||
|
||||
private static String USERNAME = "test@saml.user";
|
||||
|
||||
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 static SecretKey SECRET_KEY =
|
||||
new SecretKeySpec(Base64.getDecoder().decode("shOnwNMoCv88HKMEa91+FlYoD5RNvzMTAL5LGxZKIFk="), "AES");
|
||||
|
||||
private static SecretKey SECRET_KEY = new SecretKeySpec(
|
||||
Base64.getDecoder().decode("shOnwNMoCv88HKMEa91+FlYoD5RNvzMTAL5LGxZKIFk="), "AES");
|
||||
|
||||
static Response response() {
|
||||
return response(DESTINATION, ASSERTING_PARTY_ENTITY_ID);
|
||||
@@ -98,7 +104,7 @@ final class TestOpenSamlObjects {
|
||||
|
||||
static Response response(String destination, String issuerEntityId) {
|
||||
Response response = build(Response.DEFAULT_ELEMENT_NAME);
|
||||
response.setID("R"+UUID.randomUUID().toString());
|
||||
response.setID("R" + UUID.randomUUID().toString());
|
||||
response.setIssueInstant(DateTime.now());
|
||||
response.setVersion(SAMLVersion.VERSION_20);
|
||||
response.setID("_" + UUID.randomUUID().toString());
|
||||
@@ -111,14 +117,9 @@ final class TestOpenSamlObjects {
|
||||
return assertion(USERNAME, ASSERTING_PARTY_ENTITY_ID, RELYING_PARTY_ENTITY_ID, DESTINATION);
|
||||
}
|
||||
|
||||
static Assertion assertion(
|
||||
String username,
|
||||
String issuerEntityId,
|
||||
String recipientEntityId,
|
||||
String recipientUri
|
||||
) {
|
||||
static Assertion assertion(String username, String issuerEntityId, String recipientEntityId, String recipientUri) {
|
||||
Assertion assertion = build(Assertion.DEFAULT_ELEMENT_NAME);
|
||||
assertion.setID("A"+ UUID.randomUUID().toString());
|
||||
assertion.setID("A" + UUID.randomUUID().toString());
|
||||
assertion.setIssueInstant(DateTime.now());
|
||||
assertion.setVersion(SAMLVersion.VERSION_20);
|
||||
assertion.setIssueInstant(DateTime.now());
|
||||
@@ -135,7 +136,6 @@ final class TestOpenSamlObjects {
|
||||
return assertion;
|
||||
}
|
||||
|
||||
|
||||
static Issuer issuer(String entityId) {
|
||||
Issuer issuer = build(Issuer.DEFAULT_ELEMENT_NAME);
|
||||
issuer.setValue(entityId);
|
||||
@@ -184,7 +184,8 @@ final class TestOpenSamlObjects {
|
||||
return cred;
|
||||
}
|
||||
|
||||
static Credential getSigningCredential(org.springframework.security.saml2.credentials.Saml2X509Credential credential, String entityId) {
|
||||
static Credential getSigningCredential(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential credential, String entityId) {
|
||||
BasicCredential cred = getBasicCredential(credential);
|
||||
cred.setEntityId(entityId);
|
||||
cred.setUsageType(UsageType.SIGNING);
|
||||
@@ -192,17 +193,12 @@ final class TestOpenSamlObjects {
|
||||
}
|
||||
|
||||
static BasicCredential getBasicCredential(Saml2X509Credential credential) {
|
||||
return CredentialSupport.getSimpleCredential(
|
||||
credential.getCertificate(),
|
||||
credential.getPrivateKey()
|
||||
);
|
||||
return CredentialSupport.getSimpleCredential(credential.getCertificate(), credential.getPrivateKey());
|
||||
}
|
||||
|
||||
static BasicCredential getBasicCredential(org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
return CredentialSupport.getSimpleCredential(
|
||||
credential.getCertificate(),
|
||||
credential.getPrivateKey()
|
||||
);
|
||||
static BasicCredential getBasicCredential(
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
return CredentialSupport.getSimpleCredential(credential.getCertificate(), credential.getPrivateKey());
|
||||
}
|
||||
|
||||
static <T extends SignableSAMLObject> T signed(T signable, Saml2X509Credential credential, String entityId) {
|
||||
@@ -214,14 +210,16 @@ final class TestOpenSamlObjects {
|
||||
parameters.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
|
||||
try {
|
||||
SignatureSupport.signObject(signable, parameters);
|
||||
} catch (MarshallingException | SignatureException | SecurityException e) {
|
||||
}
|
||||
catch (MarshallingException | SignatureException | SecurityException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
|
||||
return signable;
|
||||
}
|
||||
|
||||
static <T extends SignableSAMLObject> T signed(T signable, org.springframework.security.saml2.credentials.Saml2X509Credential credential, String entityId) {
|
||||
static <T extends SignableSAMLObject> T signed(T signable,
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential credential, String entityId) {
|
||||
SignatureSigningParameters parameters = new SignatureSigningParameters();
|
||||
Credential signingCredential = getSigningCredential(credential, entityId);
|
||||
parameters.setSigningCredential(signingCredential);
|
||||
@@ -230,7 +228,8 @@ final class TestOpenSamlObjects {
|
||||
parameters.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
|
||||
try {
|
||||
SignatureSupport.signObject(signable, parameters);
|
||||
} catch (MarshallingException | SignatureException | SecurityException e) {
|
||||
}
|
||||
catch (MarshallingException | SignatureException | SecurityException e) {
|
||||
throw new Saml2Exception(e);
|
||||
}
|
||||
|
||||
@@ -248,7 +247,8 @@ final class TestOpenSamlObjects {
|
||||
}
|
||||
}
|
||||
|
||||
static EncryptedAssertion encrypted(Assertion assertion, org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
static EncryptedAssertion encrypted(Assertion assertion,
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
X509Certificate certificate = credential.getCertificate();
|
||||
Encrypter encrypter = getEncrypter(certificate);
|
||||
try {
|
||||
@@ -270,7 +270,8 @@ final class TestOpenSamlObjects {
|
||||
}
|
||||
}
|
||||
|
||||
static EncryptedID encrypted(NameID nameId, org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
static EncryptedID encrypted(NameID nameId,
|
||||
org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
|
||||
X509Certificate certificate = credential.getCertificate();
|
||||
Encrypter encrypter = getEncrypter(certificate);
|
||||
try {
|
||||
@@ -347,14 +348,16 @@ final class TestOpenSamlObjects {
|
||||
|
||||
Attribute registeredAttr = attributeBuilder.buildObject();
|
||||
registeredAttr.setName("registered");
|
||||
XSBoolean registered = new XSBooleanBuilder().buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSBoolean.TYPE_NAME);
|
||||
XSBoolean registered = new XSBooleanBuilder().buildObject(AttributeValue.DEFAULT_ELEMENT_NAME,
|
||||
XSBoolean.TYPE_NAME);
|
||||
registered.setValue(new XSBooleanValue(true, false));
|
||||
registeredAttr.getAttributeValues().add(registered);
|
||||
attrStmt2.getAttributes().add(registeredAttr);
|
||||
|
||||
Attribute registeredDateAttr = attributeBuilder.buildObject();
|
||||
registeredDateAttr.setName("registeredDate");
|
||||
XSDateTime registeredDate = new XSDateTimeBuilder().buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSDateTime.TYPE_NAME);
|
||||
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);
|
||||
attrStmt2.getAttributes().add(registeredDateAttr);
|
||||
@@ -367,4 +370,5 @@ final class TestOpenSamlObjects {
|
||||
static <T extends XMLObject> T build(QName qName) {
|
||||
return (T) getBuilderFactory().getBuilder(qName).buildObject(qName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -22,11 +22,11 @@ import static org.springframework.security.saml2.provider.service.registration.T
|
||||
* Test {@link Saml2AuthenticationRequestContext}s
|
||||
*/
|
||||
public class TestSaml2AuthenticationRequestContexts {
|
||||
|
||||
public static Saml2AuthenticationRequestContext.Builder authenticationRequestContext() {
|
||||
return Saml2AuthenticationRequestContext.builder()
|
||||
.relayState("relayState")
|
||||
.issuer("issuer")
|
||||
return Saml2AuthenticationRequestContext.builder().relayState("relayState").issuer("issuer")
|
||||
.relyingPartyRegistration(relyingPartyRegistration().build())
|
||||
.assertionConsumerServiceUrl("assertionConsumerServiceUrl");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-16
@@ -34,20 +34,15 @@ public class OpenSamlMetadataResolverTests {
|
||||
@Test
|
||||
public void resolveWhenRelyingPartyThenMetadataMatches() {
|
||||
// given
|
||||
RelyingPartyRegistration relyingPartyRegistration = full()
|
||||
.assertionConsumerServiceBinding(REDIRECT)
|
||||
.build();
|
||||
RelyingPartyRegistration relyingPartyRegistration = full().assertionConsumerServiceBinding(REDIRECT).build();
|
||||
OpenSamlMetadataResolver openSamlMetadataResolver = new OpenSamlMetadataResolver();
|
||||
|
||||
// when
|
||||
String metadata = openSamlMetadataResolver.resolve(relyingPartyRegistration);
|
||||
|
||||
// then
|
||||
assertThat(metadata)
|
||||
.contains("<EntityDescriptor")
|
||||
.contains("entityID=\"rp-entity-id\"")
|
||||
.contains("WantAssertionsSigned=\"true\"")
|
||||
.contains("<md:KeyDescriptor use=\"signing\">")
|
||||
assertThat(metadata).contains("<EntityDescriptor").contains("entityID=\"rp-entity-id\"")
|
||||
.contains("WantAssertionsSigned=\"true\"").contains("<md:KeyDescriptor use=\"signing\">")
|
||||
.contains("<md:KeyDescriptor use=\"encryption\">")
|
||||
.contains("<ds:X509Certificate>MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBh")
|
||||
.contains("Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\"")
|
||||
@@ -58,9 +53,8 @@ public class OpenSamlMetadataResolverTests {
|
||||
public void resolveWhenRelyingPartyNoCredentialsThenMetadataMatches() {
|
||||
// given
|
||||
RelyingPartyRegistration relyingPartyRegistration = noCredentials()
|
||||
.assertingPartyDetails(party -> party
|
||||
.verificationX509Credentials(c -> c.add(relyingPartyVerifyingCredential()))
|
||||
)
|
||||
.assertingPartyDetails(
|
||||
party -> party.verificationX509Credentials(c -> c.add(relyingPartyVerifyingCredential())))
|
||||
.build();
|
||||
OpenSamlMetadataResolver openSamlMetadataResolver = new OpenSamlMetadataResolver();
|
||||
|
||||
@@ -68,13 +62,11 @@ public class OpenSamlMetadataResolverTests {
|
||||
String metadata = openSamlMetadataResolver.resolve(relyingPartyRegistration);
|
||||
|
||||
// then
|
||||
assertThat(metadata)
|
||||
.contains("<EntityDescriptor")
|
||||
.contains("entityID=\"rp-entity-id\"")
|
||||
.contains("WantAssertionsSigned=\"true\"")
|
||||
.doesNotContain("<md:KeyDescriptor use=\"signing\">")
|
||||
assertThat(metadata).contains("<EntityDescriptor").contains("entityID=\"rp-entity-id\"")
|
||||
.contains("WantAssertionsSigned=\"true\"").doesNotContain("<md:KeyDescriptor use=\"signing\">")
|
||||
.doesNotContain("<md:KeyDescriptor use=\"encryption\">")
|
||||
.contains("Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"")
|
||||
.contains("Location=\"https://rp.example.org/acs\" index=\"1\"");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+40
-58
@@ -33,30 +33,24 @@ import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverterTests {
|
||||
private static final String CERTIFICATE =
|
||||
"MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYDVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwXc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0BwaXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAaBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQDDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlrQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduOnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+vZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLuxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6zV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk";
|
||||
|
||||
private static final String ENTITY_DESCRIPTOR_TEMPLATE =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||
"<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" " +
|
||||
"entityID=\"entity-id\" " +
|
||||
"ID=\"_bf133aac099b99b3d81286e1a341f2d34188043a77fe15bf4bf1487dae9b2ea3\">\n%s" +
|
||||
"</md:EntityDescriptor>";
|
||||
private static final String IDP_SSO_DESCRIPTOR_TEMPLATE =
|
||||
"<md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n" +
|
||||
"%s\n" +
|
||||
"</md:IDPSSODescriptor>";
|
||||
private static final String KEY_DESCRIPTOR_TEMPLATE =
|
||||
"<md:KeyDescriptor %s>\n" +
|
||||
"<ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n" +
|
||||
"<ds:X509Data>\n" +
|
||||
"<ds:X509Certificate>" + CERTIFICATE + "</ds:X509Certificate>\n" +
|
||||
"</ds:X509Data>\n" +
|
||||
"</ds:KeyInfo>\n" +
|
||||
"</md:KeyDescriptor>";
|
||||
private static final String SINGLE_SIGN_ON_SERVICE_TEMPLATE =
|
||||
"<md:SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" " +
|
||||
"Location=\"sso-location\"/>";
|
||||
private static final String CERTIFICATE = "MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYDVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwXc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0BwaXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAaBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQDDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlrQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWWRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gphiJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduOnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+vZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLuxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6zV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk";
|
||||
|
||||
private static final String ENTITY_DESCRIPTOR_TEMPLATE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<md:EntityDescriptor xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\" " + "entityID=\"entity-id\" "
|
||||
+ "ID=\"_bf133aac099b99b3d81286e1a341f2d34188043a77fe15bf4bf1487dae9b2ea3\">\n%s"
|
||||
+ "</md:EntityDescriptor>";
|
||||
|
||||
private static final String IDP_SSO_DESCRIPTOR_TEMPLATE = "<md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n"
|
||||
+ "%s\n" + "</md:IDPSSODescriptor>";
|
||||
|
||||
private static final String KEY_DESCRIPTOR_TEMPLATE = "<md:KeyDescriptor %s>\n"
|
||||
+ "<ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">\n" + "<ds:X509Data>\n"
|
||||
+ "<ds:X509Certificate>" + CERTIFICATE + "</ds:X509Certificate>\n" + "</ds:X509Data>\n" + "</ds:KeyInfo>\n"
|
||||
+ "</md:KeyDescriptor>";
|
||||
|
||||
private static final String SINGLE_SIGN_ON_SERVICE_TEMPLATE = "<md:SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" "
|
||||
+ "Location=\"sso-location\"/>";
|
||||
|
||||
private OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter converter;
|
||||
|
||||
@@ -67,8 +61,8 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverterTests {
|
||||
|
||||
@Test
|
||||
public void readWhenMissingIDPSSODescriptorThenException() {
|
||||
MockClientHttpResponse response = new MockClientHttpResponse
|
||||
((String.format(ENTITY_DESCRIPTOR_TEMPLATE, "")).getBytes(), OK);
|
||||
MockClientHttpResponse response = new MockClientHttpResponse(
|
||||
(String.format(ENTITY_DESCRIPTOR_TEMPLATE, "")).getBytes(), OK);
|
||||
assertThatCode(() -> this.converter.read(RelyingPartyRegistration.Builder.class, response))
|
||||
.isInstanceOf(Saml2Exception.class)
|
||||
.hasMessageContaining("Metadata response is missing the necessary IDPSSODescriptor element");
|
||||
@@ -76,41 +70,34 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverterTests {
|
||||
|
||||
@Test
|
||||
public void readWhenMissingVerificationKeyThenException() {
|
||||
String payload = String.format(ENTITY_DESCRIPTOR_TEMPLATE,
|
||||
String.format(IDP_SSO_DESCRIPTOR_TEMPLATE, ""));
|
||||
String payload = String.format(ENTITY_DESCRIPTOR_TEMPLATE, String.format(IDP_SSO_DESCRIPTOR_TEMPLATE, ""));
|
||||
MockClientHttpResponse response = new MockClientHttpResponse(payload.getBytes(), OK);
|
||||
assertThatCode(() -> this.converter.read(RelyingPartyRegistration.Builder.class, response))
|
||||
.isInstanceOf(Saml2Exception.class)
|
||||
.hasMessageContaining("Metadata response is missing verification certificates, necessary for verifying SAML assertions");
|
||||
.isInstanceOf(Saml2Exception.class).hasMessageContaining(
|
||||
"Metadata response is missing verification certificates, necessary for verifying SAML assertions");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readWhenMissingSingleSignOnServiceThenException() {
|
||||
String payload = String.format(ENTITY_DESCRIPTOR_TEMPLATE,
|
||||
String.format(IDP_SSO_DESCRIPTOR_TEMPLATE,
|
||||
String.format(KEY_DESCRIPTOR_TEMPLATE, "use=\"signing\"")
|
||||
));
|
||||
String.format(IDP_SSO_DESCRIPTOR_TEMPLATE, String.format(KEY_DESCRIPTOR_TEMPLATE, "use=\"signing\"")));
|
||||
MockClientHttpResponse response = new MockClientHttpResponse(payload.getBytes(), OK);
|
||||
assertThatCode(() -> this.converter.read(RelyingPartyRegistration.Builder.class, response))
|
||||
.isInstanceOf(Saml2Exception.class)
|
||||
.hasMessageContaining("Metadata response is missing a SingleSignOnService, necessary for sending AuthnRequests");
|
||||
.isInstanceOf(Saml2Exception.class).hasMessageContaining(
|
||||
"Metadata response is missing a SingleSignOnService, necessary for sending AuthnRequests");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readWhenDescriptorFullySpecifiedThenConfigures() throws Exception {
|
||||
String payload = String.format(ENTITY_DESCRIPTOR_TEMPLATE,
|
||||
String.format(IDP_SSO_DESCRIPTOR_TEMPLATE,
|
||||
String.format(KEY_DESCRIPTOR_TEMPLATE, "use=\"signing\"") +
|
||||
String.format(KEY_DESCRIPTOR_TEMPLATE, "use=\"encryption\"") +
|
||||
String.format(SINGLE_SIGN_ON_SERVICE_TEMPLATE)
|
||||
));
|
||||
String.format(KEY_DESCRIPTOR_TEMPLATE, "use=\"signing\"")
|
||||
+ String.format(KEY_DESCRIPTOR_TEMPLATE, "use=\"encryption\"")
|
||||
+ String.format(SINGLE_SIGN_ON_SERVICE_TEMPLATE)));
|
||||
MockClientHttpResponse response = new MockClientHttpResponse(payload.getBytes(), OK);
|
||||
RelyingPartyRegistration registration =
|
||||
this.converter.read(RelyingPartyRegistration.Builder.class, response)
|
||||
.registrationId("one")
|
||||
.build();
|
||||
RelyingPartyRegistration.AssertingPartyDetails details =
|
||||
registration.getAssertingPartyDetails();
|
||||
RelyingPartyRegistration registration = this.converter.read(RelyingPartyRegistration.Builder.class, response)
|
||||
.registrationId("one").build();
|
||||
RelyingPartyRegistration.AssertingPartyDetails details = registration.getAssertingPartyDetails();
|
||||
assertThat(details.getWantAuthnRequestsSigned()).isFalse();
|
||||
assertThat(details.getSingleSignOnServiceLocation()).isEqualTo("sso-location");
|
||||
assertThat(details.getSingleSignOnServiceBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
|
||||
@@ -125,18 +112,12 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverterTests {
|
||||
|
||||
@Test
|
||||
public void readWhenKeyDescriptorHasNoUseThenConfiguresBothKeyTypes() throws Exception {
|
||||
String payload = String.format(ENTITY_DESCRIPTOR_TEMPLATE,
|
||||
String.format(IDP_SSO_DESCRIPTOR_TEMPLATE,
|
||||
String.format(KEY_DESCRIPTOR_TEMPLATE, "") +
|
||||
String.format(SINGLE_SIGN_ON_SERVICE_TEMPLATE)
|
||||
));
|
||||
String payload = String.format(ENTITY_DESCRIPTOR_TEMPLATE, String.format(IDP_SSO_DESCRIPTOR_TEMPLATE,
|
||||
String.format(KEY_DESCRIPTOR_TEMPLATE, "") + String.format(SINGLE_SIGN_ON_SERVICE_TEMPLATE)));
|
||||
MockClientHttpResponse response = new MockClientHttpResponse(payload.getBytes(), OK);
|
||||
RelyingPartyRegistration registration =
|
||||
this.converter.read(RelyingPartyRegistration.Builder.class, response)
|
||||
.registrationId("one")
|
||||
.build();
|
||||
RelyingPartyRegistration.AssertingPartyDetails details =
|
||||
registration.getAssertingPartyDetails();
|
||||
RelyingPartyRegistration registration = this.converter.read(RelyingPartyRegistration.Builder.class, response)
|
||||
.registrationId("one").build();
|
||||
RelyingPartyRegistration.AssertingPartyDetails details = registration.getAssertingPartyDetails();
|
||||
assertThat(details.getVerificationX509Credentials().iterator().next().getCertificate())
|
||||
.isEqualTo(x509Certificate(CERTIFICATE));
|
||||
assertThat(details.getEncryptionX509Credentials()).hasSize(1);
|
||||
@@ -147,10 +128,11 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverterTests {
|
||||
X509Certificate x509Certificate(String data) {
|
||||
try {
|
||||
InputStream certificate = new ByteArrayInputStream(Base64.getDecoder().decode(data.getBytes()));
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509")
|
||||
.generateCertificate(certificate);
|
||||
} catch (Exception e) {
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certificate);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-40
@@ -30,21 +30,16 @@ public class RelyingPartyRegistrationTests {
|
||||
|
||||
@Test
|
||||
public void withRelyingPartyRegistrationWorks() {
|
||||
RelyingPartyRegistration registration = relyingPartyRegistration()
|
||||
.providerDetails(p -> p.binding(POST))
|
||||
RelyingPartyRegistration registration = relyingPartyRegistration().providerDetails(p -> p.binding(POST))
|
||||
.providerDetails(p -> p.signAuthNRequest(false))
|
||||
.assertionConsumerServiceBinding(Saml2MessageBinding.REDIRECT)
|
||||
.build();
|
||||
.assertionConsumerServiceBinding(Saml2MessageBinding.REDIRECT).build();
|
||||
RelyingPartyRegistration copy = RelyingPartyRegistration.withRelyingPartyRegistration(registration).build();
|
||||
compareRegistrations(registration, copy);
|
||||
}
|
||||
|
||||
private void compareRegistrations(RelyingPartyRegistration registration, RelyingPartyRegistration copy) {
|
||||
assertThat(copy.getRegistrationId())
|
||||
.isEqualTo(registration.getRegistrationId())
|
||||
.isEqualTo("simplesamlphp");
|
||||
assertThat(copy.getProviderDetails().getEntityId())
|
||||
.isEqualTo(registration.getProviderDetails().getEntityId())
|
||||
assertThat(copy.getRegistrationId()).isEqualTo(registration.getRegistrationId()).isEqualTo("simplesamlphp");
|
||||
assertThat(copy.getProviderDetails().getEntityId()).isEqualTo(registration.getProviderDetails().getEntityId())
|
||||
.isEqualTo(copy.getAssertingPartyDetails().getEntityId())
|
||||
.isEqualTo(registration.getAssertingPartyDetails().getEntityId())
|
||||
.isEqualTo("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php");
|
||||
@@ -53,38 +48,26 @@ public class RelyingPartyRegistrationTests {
|
||||
.isEqualTo(copy.getAssertionConsumerServiceLocation())
|
||||
.isEqualTo(registration.getAssertionConsumerServiceLocation())
|
||||
.isEqualTo("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI);
|
||||
assertThat(copy.getCredentials())
|
||||
.containsAll(registration.getCredentials())
|
||||
.containsExactly(
|
||||
registration.getCredentials().get(0),
|
||||
registration.getCredentials().get(1)
|
||||
);
|
||||
assertThat(copy.getLocalEntityIdTemplate())
|
||||
.isEqualTo(registration.getLocalEntityIdTemplate())
|
||||
.isEqualTo(copy.getEntityId())
|
||||
.isEqualTo(registration.getEntityId())
|
||||
assertThat(copy.getCredentials()).containsAll(registration.getCredentials())
|
||||
.containsExactly(registration.getCredentials().get(0), registration.getCredentials().get(1));
|
||||
assertThat(copy.getLocalEntityIdTemplate()).isEqualTo(registration.getLocalEntityIdTemplate())
|
||||
.isEqualTo(copy.getEntityId()).isEqualTo(registration.getEntityId())
|
||||
.isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}");
|
||||
assertThat(copy.getProviderDetails().getWebSsoUrl())
|
||||
.isEqualTo(registration.getProviderDetails().getWebSsoUrl())
|
||||
assertThat(copy.getProviderDetails().getWebSsoUrl()).isEqualTo(registration.getProviderDetails().getWebSsoUrl())
|
||||
.isEqualTo(copy.getAssertingPartyDetails().getSingleSignOnServiceLocation())
|
||||
.isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceLocation())
|
||||
.isEqualTo("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php");
|
||||
assertThat(copy.getProviderDetails().getBinding())
|
||||
.isEqualTo(registration.getProviderDetails().getBinding())
|
||||
assertThat(copy.getProviderDetails().getBinding()).isEqualTo(registration.getProviderDetails().getBinding())
|
||||
.isEqualTo(copy.getAssertingPartyDetails().getSingleSignOnServiceBinding())
|
||||
.isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceBinding())
|
||||
.isEqualTo(POST);
|
||||
.isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceBinding()).isEqualTo(POST);
|
||||
assertThat(copy.getProviderDetails().isSignAuthNRequest())
|
||||
.isEqualTo(registration.getProviderDetails().isSignAuthNRequest())
|
||||
.isEqualTo(copy.getAssertingPartyDetails().getWantAuthnRequestsSigned())
|
||||
.isEqualTo(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned())
|
||||
.isFalse();
|
||||
.isEqualTo(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()).isFalse();
|
||||
assertThat(copy.getAssertionConsumerServiceBinding())
|
||||
.isEqualTo(registration.getAssertionConsumerServiceBinding());
|
||||
assertThat(copy.getDecryptionX509Credentials())
|
||||
.isEqualTo(registration.getDecryptionX509Credentials());
|
||||
assertThat(copy.getSigningX509Credentials())
|
||||
.isEqualTo(registration.getSigningX509Credentials());
|
||||
assertThat(copy.getDecryptionX509Credentials()).isEqualTo(registration.getDecryptionX509Credentials());
|
||||
assertThat(copy.getSigningX509Credentials()).isEqualTo(registration.getSigningX509Credentials());
|
||||
assertThat(copy.getAssertingPartyDetails().getEncryptionX509Credentials())
|
||||
.isEqualTo(registration.getAssertingPartyDetails().getEncryptionX509Credentials());
|
||||
assertThat(copy.getAssertingPartyDetails().getVerificationX509Credentials())
|
||||
@@ -93,16 +76,13 @@ public class RelyingPartyRegistrationTests {
|
||||
|
||||
@Test
|
||||
public void buildWhenUsingDefaultsThenAssertionConsumerServiceBindingDefaultsToPost() {
|
||||
RelyingPartyRegistration relyingPartyRegistration = withRegistrationId("id")
|
||||
.entityId("entity-id")
|
||||
RelyingPartyRegistration relyingPartyRegistration = withRegistrationId("id").entityId("entity-id")
|
||||
.assertionConsumerServiceLocation("location")
|
||||
.assertingPartyDetails(assertingParty -> assertingParty
|
||||
.entityId("entity-id")
|
||||
.singleSignOnServiceLocation("location"))
|
||||
.credentials(c -> c.add(relyingPartyVerifyingCredential()))
|
||||
.build();
|
||||
.assertingPartyDetails(
|
||||
assertingParty -> assertingParty.entityId("entity-id").singleSignOnServiceLocation("location"))
|
||||
.credentials(c -> c.add(relyingPartyVerifyingCredential())).build();
|
||||
|
||||
assertThat(relyingPartyRegistration.getAssertionConsumerServiceBinding())
|
||||
.isEqualTo(POST);
|
||||
assertThat(relyingPartyRegistration.getAssertionConsumerServiceBinding()).isEqualTo(POST);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+57
-92
@@ -29,108 +29,72 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
|
||||
* Tests for {@link RelyingPartyRegistration}
|
||||
*/
|
||||
public class RelyingPartyRegistrationsTests {
|
||||
private static final String IDP_SSO_DESCRIPTOR_PAYLOAD =
|
||||
"<md:EntityDescriptor entityID=\"https://idp.example.com/idp/shibboleth\"\n" +
|
||||
" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"\n" +
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
|
||||
" xmlns:shibmd=\"urn:mace:shibboleth:metadata:1.0\"\n" +
|
||||
" xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n" +
|
||||
" xmlns:mdui=\"urn:oasis:names:tc:SAML:metadata:ui\">\n" +
|
||||
" \n" +
|
||||
" <md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n" +
|
||||
" <md:Extensions>\n" +
|
||||
" <shibmd:Scope regexp=\"false\">example.com</shibmd:Scope>\n" +
|
||||
" \n" +
|
||||
" <mdui:UIInfo>\n" +
|
||||
" <mdui:DisplayName xml:lang=\"en\">\n" +
|
||||
" Consortium GARR IdP\n" +
|
||||
" </mdui:DisplayName>\n" +
|
||||
" <mdui:DisplayName xml:lang=\"it\">\n" +
|
||||
" Consortium GARR IdP\n" +
|
||||
" </mdui:DisplayName>\n" +
|
||||
" \n" +
|
||||
" <mdui:Description xml:lang=\"en\">\n" +
|
||||
" This Identity Provider gives support for the Consortium GARR's user community\n" +
|
||||
" </mdui:Description>\n" +
|
||||
" <mdui:Description xml:lang=\"it\">\n" +
|
||||
" Questo Identity Provider di test fornisce supporto alla comunita' utenti GARR\n" +
|
||||
" </mdui:Description>\n" +
|
||||
" </mdui:UIInfo>\n" +
|
||||
" </md:Extensions>\n" +
|
||||
" \n" +
|
||||
" <md:KeyDescriptor>\n" +
|
||||
" <ds:KeyInfo>\n" +
|
||||
" <ds:X509Data>\n" +
|
||||
" <ds:X509Certificate>\n" +
|
||||
" MIIDZjCCAk6gAwIBAgIVAL9O+PA7SXtlwZZY8MVSE9On1cVWMA0GCSqGSIb3DQEB\n" +
|
||||
" BQUAMCkxJzAlBgNVBAMTHmlkZW0tcHVwYWdlbnQuZG16LWludC51bmltby5pdDAe\n" +
|
||||
" Fw0xMzA3MjQwMDQ0MTRaFw0zMzA3MjQwMDQ0MTRaMCkxJzAlBgNVBAMTHmlkZW0t\n" +
|
||||
" cHVwYWdlbnQuZG16LWludC51bmltby5pdDCCASIwDQYJKoZIhvcNAMIIDQADggEP\n" +
|
||||
" ADCCAQoCggEBAIAcp/VyzZGXUF99kwj4NvL/Rwv4YvBgLWzpCuoxqHZ/hmBwJtqS\n" +
|
||||
" v0y9METBPFbgsF3hCISnxbcmNVxf/D0MoeKtw1YPbsUmow/bFe+r72hZ+IVAcejN\n" +
|
||||
" iDJ7t5oTjsRN1t1SqvVVk6Ryk5AZhpFW+W9pE9N6c7kJ16Rp2/mbtax9OCzxpece\n" +
|
||||
" byi1eiLfIBmkcRawL/vCc2v6VLI18i6HsNVO3l2yGosKCbuSoGDx2fCdAOk/rgdz\n" +
|
||||
" cWOvFsIZSKuD+FVbSS/J9GVs7yotsS4PRl4iX9UMnfDnOMfO7bcBgbXtDl4SCU1v\n" +
|
||||
" dJrRw7IL/pLz34Rv9a8nYitrzrxtLOp3nYUCAwEAAaOBhDCBgTBgBgMIIDEEWTBX\n" +
|
||||
" gh5pZGVtLXB1cGFnZW50LmRtei1pbnQudW5pbW8uaXSGNWh0dHBzOi8vaWRlbS1w\n" +
|
||||
" dXBhZ2VudC5kbXotaW50LnVuaW1vLml0L2lkcC9zaGliYm9sZXRoMB0GA1UdDgQW\n" +
|
||||
" BBT8PANzz+adGnTRe8ldcyxAwe4VnzANBgkqhkiG9w0BAQUFAAOCAQEAOEnO8Clu\n" +
|
||||
" 9z/Lf/8XOOsTdxJbV29DIF3G8KoQsB3dBsLwPZVEAQIP6ceS32Xaxrl6FMTDDNkL\n" +
|
||||
" qUvvInUisw0+I5zZwYHybJQCletUWTnz58SC4C9G7FpuXHFZnOGtRcgGD1NOX4UU\n" +
|
||||
" duus/4nVcGSLhDjszZ70Xtj0gw2Sn46oQPHTJ81QZ3Y9ih+Aj1c9OtUSBwtWZFkU\n" +
|
||||
" yooAKoR8li68Yb21zN2N65AqV+ndL98M8xUYMKLONuAXStDeoVCipH6PJ09Z5U2p\n" +
|
||||
" V5p4IQRV6QBsNw9CISJFuHzkVYTH5ZxzN80Ru46vh4y2M0Nu8GQ9I085KoZkrf5e\n" +
|
||||
" Cq53OZt9ISjHEw==\n" +
|
||||
" </ds:X509Certificate>\n" +
|
||||
" </ds:X509Data>\n" +
|
||||
" </ds:KeyInfo>\n" +
|
||||
" </md:KeyDescriptor>\n" +
|
||||
" \n" +
|
||||
" <md:SingleSignOnService\n" +
|
||||
" Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n" +
|
||||
" Location=\"https://idp.example.com/idp/profile/SAML2/POST/SSO\"/>\n" +
|
||||
" </md:IDPSSODescriptor>\n" +
|
||||
" \n" +
|
||||
" <md:Organization>\n" +
|
||||
" <md:OrganizationName xml:lang=\"en\">\n" +
|
||||
" Consortium GARR\n" +
|
||||
" </md:OrganizationName>\n" +
|
||||
" <md:OrganizationName xml:lang=\"it\">\n" +
|
||||
" Consortium GARR\n" +
|
||||
" </md:OrganizationName>\n" +
|
||||
" \n" +
|
||||
" <md:OrganizationDisplayName xml:lang=\"en\">\n" +
|
||||
" Consortium GARR\n" +
|
||||
" </md:OrganizationDisplayName>\n" +
|
||||
" <md:OrganizationDisplayName xml:lang=\"it\">\n" +
|
||||
" Consortium GARR\n" +
|
||||
" </md:OrganizationDisplayName>\n" +
|
||||
" \n" +
|
||||
" <md:OrganizationURL xml:lang=\"it\">\n" +
|
||||
" https://example.org\n" +
|
||||
" </md:OrganizationURL>\n" +
|
||||
" </md:Organization>\n" +
|
||||
" \n" +
|
||||
" <md:ContactPerson contactType=\"technical\">\n" +
|
||||
" <md:EmailAddress>mailto:technical.contact@example.com</md:EmailAddress>\n" +
|
||||
" </md:ContactPerson>\n" +
|
||||
" \n" +
|
||||
"</md:EntityDescriptor>";
|
||||
|
||||
private static final String IDP_SSO_DESCRIPTOR_PAYLOAD = "<md:EntityDescriptor entityID=\"https://idp.example.com/idp/shibboleth\"\n"
|
||||
+ " xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"\n"
|
||||
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
+ " xmlns:shibmd=\"urn:mace:shibboleth:metadata:1.0\"\n"
|
||||
+ " xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n"
|
||||
+ " xmlns:mdui=\"urn:oasis:names:tc:SAML:metadata:ui\">\n" + " \n"
|
||||
+ " <md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n"
|
||||
+ " <md:Extensions>\n" + " <shibmd:Scope regexp=\"false\">example.com</shibmd:Scope>\n"
|
||||
+ " \n" + " <mdui:UIInfo>\n" + " <mdui:DisplayName xml:lang=\"en\">\n"
|
||||
+ " Consortium GARR IdP\n" + " </mdui:DisplayName>\n"
|
||||
+ " <mdui:DisplayName xml:lang=\"it\">\n" + " Consortium GARR IdP\n"
|
||||
+ " </mdui:DisplayName>\n" + " \n" + " <mdui:Description xml:lang=\"en\">\n"
|
||||
+ " This Identity Provider gives support for the Consortium GARR's user community\n"
|
||||
+ " </mdui:Description>\n" + " <mdui:Description xml:lang=\"it\">\n"
|
||||
+ " Questo Identity Provider di test fornisce supporto alla comunita' utenti GARR\n"
|
||||
+ " </mdui:Description>\n" + " </mdui:UIInfo>\n" + " </md:Extensions>\n" + " \n"
|
||||
+ " <md:KeyDescriptor>\n" + " <ds:KeyInfo>\n" + " <ds:X509Data>\n"
|
||||
+ " <ds:X509Certificate>\n"
|
||||
+ " MIIDZjCCAk6gAwIBAgIVAL9O+PA7SXtlwZZY8MVSE9On1cVWMA0GCSqGSIb3DQEB\n"
|
||||
+ " BQUAMCkxJzAlBgNVBAMTHmlkZW0tcHVwYWdlbnQuZG16LWludC51bmltby5pdDAe\n"
|
||||
+ " Fw0xMzA3MjQwMDQ0MTRaFw0zMzA3MjQwMDQ0MTRaMCkxJzAlBgNVBAMTHmlkZW0t\n"
|
||||
+ " cHVwYWdlbnQuZG16LWludC51bmltby5pdDCCASIwDQYJKoZIhvcNAMIIDQADggEP\n"
|
||||
+ " ADCCAQoCggEBAIAcp/VyzZGXUF99kwj4NvL/Rwv4YvBgLWzpCuoxqHZ/hmBwJtqS\n"
|
||||
+ " v0y9METBPFbgsF3hCISnxbcmNVxf/D0MoeKtw1YPbsUmow/bFe+r72hZ+IVAcejN\n"
|
||||
+ " iDJ7t5oTjsRN1t1SqvVVk6Ryk5AZhpFW+W9pE9N6c7kJ16Rp2/mbtax9OCzxpece\n"
|
||||
+ " byi1eiLfIBmkcRawL/vCc2v6VLI18i6HsNVO3l2yGosKCbuSoGDx2fCdAOk/rgdz\n"
|
||||
+ " cWOvFsIZSKuD+FVbSS/J9GVs7yotsS4PRl4iX9UMnfDnOMfO7bcBgbXtDl4SCU1v\n"
|
||||
+ " dJrRw7IL/pLz34Rv9a8nYitrzrxtLOp3nYUCAwEAAaOBhDCBgTBgBgMIIDEEWTBX\n"
|
||||
+ " gh5pZGVtLXB1cGFnZW50LmRtei1pbnQudW5pbW8uaXSGNWh0dHBzOi8vaWRlbS1w\n"
|
||||
+ " dXBhZ2VudC5kbXotaW50LnVuaW1vLml0L2lkcC9zaGliYm9sZXRoMB0GA1UdDgQW\n"
|
||||
+ " BBT8PANzz+adGnTRe8ldcyxAwe4VnzANBgkqhkiG9w0BAQUFAAOCAQEAOEnO8Clu\n"
|
||||
+ " 9z/Lf/8XOOsTdxJbV29DIF3G8KoQsB3dBsLwPZVEAQIP6ceS32Xaxrl6FMTDDNkL\n"
|
||||
+ " qUvvInUisw0+I5zZwYHybJQCletUWTnz58SC4C9G7FpuXHFZnOGtRcgGD1NOX4UU\n"
|
||||
+ " duus/4nVcGSLhDjszZ70Xtj0gw2Sn46oQPHTJ81QZ3Y9ih+Aj1c9OtUSBwtWZFkU\n"
|
||||
+ " yooAKoR8li68Yb21zN2N65AqV+ndL98M8xUYMKLONuAXStDeoVCipH6PJ09Z5U2p\n"
|
||||
+ " V5p4IQRV6QBsNw9CISJFuHzkVYTH5ZxzN80Ru46vh4y2M0Nu8GQ9I085KoZkrf5e\n"
|
||||
+ " Cq53OZt9ISjHEw==\n" + " </ds:X509Certificate>\n"
|
||||
+ " </ds:X509Data>\n" + " </ds:KeyInfo>\n" + " </md:KeyDescriptor>\n" + " \n"
|
||||
+ " <md:SingleSignOnService\n"
|
||||
+ " Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n"
|
||||
+ " Location=\"https://idp.example.com/idp/profile/SAML2/POST/SSO\"/>\n"
|
||||
+ " </md:IDPSSODescriptor>\n" + " \n" + " <md:Organization>\n"
|
||||
+ " <md:OrganizationName xml:lang=\"en\">\n" + " Consortium GARR\n"
|
||||
+ " </md:OrganizationName>\n" + " <md:OrganizationName xml:lang=\"it\">\n"
|
||||
+ " Consortium GARR\n" + " </md:OrganizationName>\n" + " \n"
|
||||
+ " <md:OrganizationDisplayName xml:lang=\"en\">\n" + " Consortium GARR\n"
|
||||
+ " </md:OrganizationDisplayName>\n" + " <md:OrganizationDisplayName xml:lang=\"it\">\n"
|
||||
+ " Consortium GARR\n" + " </md:OrganizationDisplayName>\n" + " \n"
|
||||
+ " <md:OrganizationURL xml:lang=\"it\">\n" + " https://example.org\n"
|
||||
+ " </md:OrganizationURL>\n" + " </md:Organization>\n" + " \n"
|
||||
+ " <md:ContactPerson contactType=\"technical\">\n"
|
||||
+ " <md:EmailAddress>mailto:technical.contact@example.com</md:EmailAddress>\n"
|
||||
+ " </md:ContactPerson>\n" + " \n" + "</md:EntityDescriptor>";
|
||||
|
||||
@Test
|
||||
public void fromMetadataLocationWhenResolvableThenPopulatesBuilder() throws Exception {
|
||||
try (MockWebServer server = new MockWebServer()) {
|
||||
server.enqueue(new MockResponse().setBody(IDP_SSO_DESCRIPTOR_PAYLOAD).setResponseCode(200));
|
||||
RelyingPartyRegistration registration = RelyingPartyRegistrations
|
||||
.fromMetadataLocation(server.url("/").toString())
|
||||
.entityId("rp")
|
||||
.build();
|
||||
.fromMetadataLocation(server.url("/").toString()).entityId("rp").build();
|
||||
RelyingPartyRegistration.AssertingPartyDetails details = registration.getAssertingPartyDetails();
|
||||
assertThat(details.getEntityId()).isEqualTo("https://idp.example.com/idp/shibboleth");
|
||||
assertThat(details.getSingleSignOnServiceLocation())
|
||||
.isEqualTo("https://idp.example.com/idp/profile/SAML2/POST/SSO");
|
||||
assertThat(details.getSingleSignOnServiceBinding())
|
||||
.isEqualTo(Saml2MessageBinding.POST);
|
||||
assertThat(details.getSingleSignOnServiceBinding()).isEqualTo(Saml2MessageBinding.POST);
|
||||
assertThat(details.getVerificationX509Credentials()).hasSize(1);
|
||||
assertThat(details.getEncryptionX509Credentials()).hasSize(1);
|
||||
}
|
||||
@@ -156,4 +120,5 @@ public class RelyingPartyRegistrationsTests {
|
||||
.isInstanceOf(Saml2Exception.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-19
@@ -33,40 +33,32 @@ public class TestRelyingPartyRegistrations {
|
||||
|
||||
String rpEntityId = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
|
||||
Saml2X509Credential signingCredential = relyingPartySigningCredential();
|
||||
String assertionConsumerServiceLocation = "{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
|
||||
String assertionConsumerServiceLocation = "{baseUrl}"
|
||||
+ Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
|
||||
|
||||
String apEntityId = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php";
|
||||
Saml2X509Credential verificationCertificate = relyingPartyVerifyingCredential();
|
||||
String singleSignOnServiceLocation = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php";
|
||||
|
||||
return RelyingPartyRegistration.withRegistrationId(registrationId)
|
||||
.entityId(rpEntityId)
|
||||
return RelyingPartyRegistration.withRegistrationId(registrationId).entityId(rpEntityId)
|
||||
.assertionConsumerServiceLocation(assertionConsumerServiceLocation)
|
||||
.credentials(c -> c.add(signingCredential))
|
||||
.providerDetails(c -> c
|
||||
.entityId(apEntityId)
|
||||
.webSsoUrl(singleSignOnServiceLocation))
|
||||
.credentials(c -> c.add(verificationCertificate));
|
||||
.providerDetails(c -> c.entityId(apEntityId).webSsoUrl(singleSignOnServiceLocation))
|
||||
.credentials(c -> c.add(verificationCertificate));
|
||||
}
|
||||
|
||||
public static RelyingPartyRegistration.Builder noCredentials() {
|
||||
return RelyingPartyRegistration.withRegistrationId("registration-id")
|
||||
.entityId("rp-entity-id")
|
||||
.assertionConsumerServiceLocation("https://rp.example.org/acs")
|
||||
.assertingPartyDetails(party -> party
|
||||
.entityId("ap-entity-id")
|
||||
.singleSignOnServiceLocation("https://ap.example.org/sso")
|
||||
);
|
||||
return RelyingPartyRegistration.withRegistrationId("registration-id").entityId("rp-entity-id")
|
||||
.assertionConsumerServiceLocation("https://rp.example.org/acs").assertingPartyDetails(party -> party
|
||||
.entityId("ap-entity-id").singleSignOnServiceLocation("https://ap.example.org/sso"));
|
||||
}
|
||||
|
||||
public static RelyingPartyRegistration.Builder full() {
|
||||
return noCredentials()
|
||||
.signingX509Credentials(c -> c.add(TestSaml2X509Credentials.relyingPartySigningCredential()))
|
||||
.decryptionX509Credentials(c -> c.add(TestSaml2X509Credentials.relyingPartyDecryptingCredential()))
|
||||
.assertingPartyDetails(party -> party
|
||||
.verificationX509Credentials(c -> c.add(
|
||||
TestSaml2X509Credentials.relyingPartyVerifyingCredential())
|
||||
)
|
||||
);
|
||||
.assertingPartyDetails(party -> party.verificationX509Credentials(
|
||||
c -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential())));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-1
@@ -36,8 +36,11 @@ import static org.mockito.Mockito.when;
|
||||
public class Saml2WebSsoAuthenticationFilterTests {
|
||||
|
||||
private Saml2WebSsoAuthenticationFilter filter;
|
||||
|
||||
private RelyingPartyRegistrationRepository repository = mock(RelyingPartyRegistrationRepository.class);
|
||||
|
||||
private MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
private HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
@Rule
|
||||
@@ -87,9 +90,11 @@ public class Saml2WebSsoAuthenticationFilterTests {
|
||||
try {
|
||||
filter.attemptAuthentication(request, response);
|
||||
failBecauseExceptionWasNotThrown(Saml2AuthenticationException.class);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e).isInstanceOf(Saml2AuthenticationException.class);
|
||||
assertThat(e.getMessage()).isEqualTo("No relying party registration found");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+41
-71
@@ -48,14 +48,21 @@ import static org.springframework.security.saml2.provider.service.registration.S
|
||||
public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
|
||||
private static final String IDP_SSO_URL = "https://sso-url.example.com/IDP/SSO";
|
||||
|
||||
private Saml2WebSsoAuthenticationRequestFilter filter;
|
||||
|
||||
private RelyingPartyRegistrationRepository repository = mock(RelyingPartyRegistrationRepository.class);
|
||||
|
||||
private Saml2AuthenticationRequestFactory factory = mock(Saml2AuthenticationRequestFactory.class);
|
||||
private Saml2AuthenticationRequestContextResolver resolver =
|
||||
mock(Saml2AuthenticationRequestContextResolver.class);
|
||||
|
||||
private Saml2AuthenticationRequestContextResolver resolver = mock(Saml2AuthenticationRequestContextResolver.class);
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private MockFilterChain filterChain;
|
||||
|
||||
private RelyingPartyRegistration.Builder rpBuilder;
|
||||
|
||||
@Before
|
||||
@@ -67,10 +74,8 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
|
||||
filterChain = new MockFilterChain();
|
||||
|
||||
rpBuilder = RelyingPartyRegistration
|
||||
.withRegistrationId("registration-id")
|
||||
.providerDetails(c -> c.entityId("idp-entity-id"))
|
||||
.providerDetails(c -> c.webSsoUrl(IDP_SSO_URL))
|
||||
rpBuilder = RelyingPartyRegistration.withRegistrationId("registration-id")
|
||||
.providerDetails(c -> c.entityId("idp-entity-id")).providerDetails(c -> c.webSsoUrl(IDP_SSO_URL))
|
||||
.assertionConsumerServiceUrlTemplate("template")
|
||||
.credentials(c -> c.add(assertingPartyPrivateCredential()));
|
||||
}
|
||||
@@ -79,9 +84,7 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
public void doFilterWhenNoRelayStateThenRedirectDoesNotContainParameter() throws ServletException, IOException {
|
||||
when(repository.findByRegistrationId("registration-id")).thenReturn(rpBuilder.build());
|
||||
filter.doFilterInternal(request, response, filterChain);
|
||||
assertThat(response.getHeader("Location"))
|
||||
.doesNotContain("RelayState=")
|
||||
.startsWith(IDP_SSO_URL);
|
||||
assertThat(response.getHeader("Location")).doesNotContain("RelayState=").startsWith(IDP_SSO_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -89,9 +92,7 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
when(repository.findByRegistrationId("registration-id")).thenReturn(rpBuilder.build());
|
||||
request.setParameter("RelayState", "my-relay-state");
|
||||
filter.doFilterInternal(request, response, filterChain);
|
||||
assertThat(response.getHeader("Location"))
|
||||
.contains("RelayState=my-relay-state")
|
||||
.startsWith(IDP_SSO_URL);
|
||||
assertThat(response.getHeader("Location")).contains("RelayState=my-relay-state").startsWith(IDP_SSO_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,53 +102,36 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
final String relayStateEncoded = UriUtils.encode(relayStateValue, StandardCharsets.ISO_8859_1);
|
||||
request.setParameter("RelayState", relayStateValue);
|
||||
filter.doFilterInternal(request, response, filterChain);
|
||||
assertThat(response.getHeader("Location"))
|
||||
.contains("RelayState="+relayStateEncoded)
|
||||
.startsWith(IDP_SSO_URL);
|
||||
assertThat(response.getHeader("Location")).contains("RelayState=" + relayStateEncoded).startsWith(IDP_SSO_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenSimpleSignatureSpecifiedThenSignatureParametersAreInTheRedirectURL() throws Exception {
|
||||
when(repository.findByRegistrationId("registration-id")).thenReturn(
|
||||
rpBuilder
|
||||
.build()
|
||||
);
|
||||
when(repository.findByRegistrationId("registration-id")).thenReturn(rpBuilder.build());
|
||||
final String relayStateValue = "https://my-relay-state.example.com?with=param&other=param";
|
||||
final String relayStateEncoded = UriUtils.encode(relayStateValue, StandardCharsets.ISO_8859_1);
|
||||
request.setParameter("RelayState", relayStateValue);
|
||||
filter.doFilterInternal(request, response, filterChain);
|
||||
assertThat(response.getHeader("Location"))
|
||||
.contains("RelayState="+relayStateEncoded)
|
||||
.contains("SigAlg=")
|
||||
.contains("Signature=")
|
||||
.startsWith(IDP_SSO_URL);
|
||||
assertThat(response.getHeader("Location")).contains("RelayState=" + relayStateEncoded).contains("SigAlg=")
|
||||
.contains("Signature=").startsWith(IDP_SSO_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenSignatureIsDisabledThenSignatureParametersAreNotInTheRedirectURL() throws Exception {
|
||||
when(repository.findByRegistrationId("registration-id")).thenReturn(
|
||||
rpBuilder
|
||||
.providerDetails(c -> c.signAuthNRequest(false))
|
||||
.build()
|
||||
);
|
||||
when(repository.findByRegistrationId("registration-id"))
|
||||
.thenReturn(rpBuilder.providerDetails(c -> c.signAuthNRequest(false)).build());
|
||||
final String relayStateValue = "https://my-relay-state.example.com?with=param&other=param";
|
||||
final String relayStateEncoded = UriUtils.encode(relayStateValue, StandardCharsets.ISO_8859_1);
|
||||
request.setParameter("RelayState", relayStateValue);
|
||||
filter.doFilterInternal(request, response, filterChain);
|
||||
assertThat(response.getHeader("Location"))
|
||||
.contains("RelayState="+relayStateEncoded)
|
||||
.doesNotContain("SigAlg=")
|
||||
.doesNotContain("Signature=")
|
||||
.startsWith(IDP_SSO_URL);
|
||||
assertThat(response.getHeader("Location")).contains("RelayState=" + relayStateEncoded).doesNotContain("SigAlg=")
|
||||
.doesNotContain("Signature=").startsWith(IDP_SSO_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenPostFormDataIsPresent() throws Exception {
|
||||
when(repository.findByRegistrationId("registration-id")).thenReturn(
|
||||
rpBuilder
|
||||
.providerDetails(c -> c.binding(POST))
|
||||
.build()
|
||||
);
|
||||
when(repository.findByRegistrationId("registration-id"))
|
||||
.thenReturn(rpBuilder.providerDetails(c -> c.binding(POST)).build());
|
||||
final String relayStateValue = "https://my-relay-state.example.com?with=param&other=param&javascript{alert('1');}";
|
||||
final String relayStateEncoded = HtmlUtils.htmlEscape(relayStateValue);
|
||||
request.setParameter("RelayState", relayStateValue);
|
||||
@@ -156,28 +140,23 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
assertThat(response.getContentAsString())
|
||||
.contains("<form action=\"https://sso-url.example.com/IDP/SSO\" method=\"post\">")
|
||||
.contains("<input type=\"hidden\" name=\"SAMLRequest\"")
|
||||
.contains("value=\""+relayStateEncoded+"\"");
|
||||
.contains("value=\"" + relayStateEncoded + "\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenSetAuthenticationRequestFactoryThenUses() throws Exception {
|
||||
RelyingPartyRegistration relyingParty = this.rpBuilder
|
||||
.providerDetails(c -> c.binding(POST))
|
||||
.build();
|
||||
RelyingPartyRegistration relyingParty = this.rpBuilder.providerDetails(c -> c.binding(POST)).build();
|
||||
Saml2PostAuthenticationRequest authenticationRequest = mock(Saml2PostAuthenticationRequest.class);
|
||||
when(authenticationRequest.getAuthenticationRequestUri()).thenReturn("uri");
|
||||
when(authenticationRequest.getRelayState()).thenReturn("relay");
|
||||
when(authenticationRequest.getSamlRequest()).thenReturn("saml");
|
||||
when(this.repository.findByRegistrationId("registration-id")).thenReturn(relyingParty);
|
||||
when(this.factory.createPostAuthenticationRequest(any()))
|
||||
.thenReturn(authenticationRequest);
|
||||
when(this.factory.createPostAuthenticationRequest(any())).thenReturn(authenticationRequest);
|
||||
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter
|
||||
(this.repository);
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.repository);
|
||||
filter.setAuthenticationRequestFactory(this.factory);
|
||||
filter.doFilterInternal(this.request, this.response, this.filterChain);
|
||||
assertThat(this.response.getContentAsString())
|
||||
.contains("<form action=\"uri\" method=\"post\">")
|
||||
assertThat(this.response.getContentAsString()).contains("<form action=\"uri\" method=\"post\">")
|
||||
.contains("<input type=\"hidden\" name=\"SAMLRequest\" value=\"saml\"")
|
||||
.contains("<input type=\"hidden\" name=\"RelayState\" value=\"relay\"");
|
||||
verify(this.factory).createPostAuthenticationRequest(any());
|
||||
@@ -185,24 +164,19 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
|
||||
@Test
|
||||
public void doFilterWhenCustomAuthenticationRequestFactoryThenUses() throws Exception {
|
||||
RelyingPartyRegistration relyingParty = this.rpBuilder
|
||||
.providerDetails(c -> c.binding(POST))
|
||||
.build();
|
||||
RelyingPartyRegistration relyingParty = this.rpBuilder.providerDetails(c -> c.binding(POST)).build();
|
||||
Saml2PostAuthenticationRequest authenticationRequest = mock(Saml2PostAuthenticationRequest.class);
|
||||
when(authenticationRequest.getAuthenticationRequestUri()).thenReturn("uri");
|
||||
when(authenticationRequest.getRelayState()).thenReturn("relay");
|
||||
when(authenticationRequest.getSamlRequest()).thenReturn("saml");
|
||||
when(this.resolver.resolve(this.request)).thenReturn(authenticationRequestContext()
|
||||
.relyingPartyRegistration(relyingParty)
|
||||
.build());
|
||||
when(this.factory.createPostAuthenticationRequest(any()))
|
||||
.thenReturn(authenticationRequest);
|
||||
when(this.resolver.resolve(this.request))
|
||||
.thenReturn(authenticationRequestContext().relyingPartyRegistration(relyingParty).build());
|
||||
when(this.factory.createPostAuthenticationRequest(any())).thenReturn(authenticationRequest);
|
||||
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter
|
||||
(this.resolver, this.factory);
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.resolver,
|
||||
this.factory);
|
||||
filter.doFilterInternal(this.request, this.response, this.filterChain);
|
||||
assertThat(this.response.getContentAsString())
|
||||
.contains("<form action=\"uri\" method=\"post\">")
|
||||
assertThat(this.response.getContentAsString()).contains("<form action=\"uri\" method=\"post\">")
|
||||
.contains("<input type=\"hidden\" name=\"SAMLRequest\" value=\"saml\"")
|
||||
.contains("<input type=\"hidden\" name=\"RelayState\" value=\"relay\"");
|
||||
verify(this.factory).createPostAuthenticationRequest(any());
|
||||
@@ -210,23 +184,19 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
|
||||
@Test
|
||||
public void setRequestMatcherWhenNullThenException() {
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter
|
||||
(this.repository);
|
||||
assertThatCode(() -> filter.setRedirectMatcher(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.repository);
|
||||
assertThatCode(() -> filter.setRedirectMatcher(null)).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationRequestFactoryWhenNullThenException() {
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.repository);
|
||||
assertThatCode(() -> filter.setAuthenticationRequestFactory(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> filter.setAuthenticationRequestFactory(null)).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenRequestMatcherFailsThenSkipsFilter() throws Exception {
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter
|
||||
(this.repository);
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.repository);
|
||||
filter.setRedirectMatcher(request -> false);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
verifyNoInteractions(this.repository);
|
||||
@@ -234,9 +204,9 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
|
||||
|
||||
@Test
|
||||
public void doFilterWhenRelyingPartyRegistrationNotFoundThenUnauthorized() throws Exception {
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter
|
||||
(this.repository);
|
||||
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.repository);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
assertThat(this.response.getStatus()).isEqualTo(401);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-6
@@ -31,11 +31,14 @@ import static org.springframework.security.saml2.provider.service.registration.T
|
||||
* Tests for {@link DefaultRelyingPartyRegistrationResolver}
|
||||
*/
|
||||
public class DefaultRelyingPartyRegistrationResolverTests {
|
||||
|
||||
private final RelyingPartyRegistration registration = relyingPartyRegistration().build();
|
||||
private final RelyingPartyRegistrationRepository repository =
|
||||
new InMemoryRelyingPartyRegistrationRepository(this.registration);
|
||||
private final DefaultRelyingPartyRegistrationResolver resolver =
|
||||
new DefaultRelyingPartyRegistrationResolver(this.repository);
|
||||
|
||||
private final RelyingPartyRegistrationRepository repository = new InMemoryRelyingPartyRegistrationRepository(
|
||||
this.registration);
|
||||
|
||||
private final DefaultRelyingPartyRegistrationResolver resolver = new DefaultRelyingPartyRegistrationResolver(
|
||||
this.repository);
|
||||
|
||||
@Test
|
||||
public void resolveWhenRequestContainsRegistrationIdThenResolves() {
|
||||
@@ -43,8 +46,7 @@ public class DefaultRelyingPartyRegistrationResolverTests {
|
||||
request.setPathInfo("/some/path/" + this.registration.getRegistrationId());
|
||||
RelyingPartyRegistration registration = this.resolver.convert(request);
|
||||
assertThat(registration).isNotNull();
|
||||
assertThat(registration.getRegistrationId())
|
||||
.isEqualTo(this.registration.getRegistrationId());
|
||||
assertThat(registration.getRegistrationId()).isEqualTo(this.registration.getRegistrationId());
|
||||
assertThat(registration.getEntityId())
|
||||
.isEqualTo("http://localhost/saml2/service-provider-metadata/" + this.registration.getRegistrationId());
|
||||
assertThat(registration.getAssertionConsumerServiceLocation())
|
||||
@@ -71,4 +73,5 @@ public class DefaultRelyingPartyRegistrationResolverTests {
|
||||
assertThatCode(() -> new DefaultRelyingPartyRegistrationResolver(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-17
@@ -36,23 +36,27 @@ import static org.springframework.security.saml2.credentials.TestSaml2X509Creden
|
||||
public class DefaultSaml2AuthenticationRequestContextResolverTests {
|
||||
|
||||
private static final String ASSERTING_PARTY_SSO_URL = "https://idp.example.com/sso";
|
||||
|
||||
private static final String RELYING_PARTY_SSO_URL = "https://sp.example.com/sso";
|
||||
|
||||
private static final String ASSERTING_PARTY_ENTITY_ID = "asserting-party-entity-id";
|
||||
|
||||
private static final String RELYING_PARTY_ENTITY_ID = "relying-party-entity-id";
|
||||
|
||||
private static final String REGISTRATION_ID = "registration-id";
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private RelyingPartyRegistration.Builder relyingPartyBuilder;
|
||||
private Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver
|
||||
= new DefaultSaml2AuthenticationRequestContextResolver(
|
||||
new DefaultRelyingPartyRegistrationResolver(id -> relyingPartyBuilder.build()));
|
||||
|
||||
private Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver = new DefaultSaml2AuthenticationRequestContextResolver(
|
||||
new DefaultRelyingPartyRegistrationResolver(id -> relyingPartyBuilder.build()));
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.request.setPathInfo("/saml2/authenticate/registration-id");
|
||||
this.relyingPartyBuilder = RelyingPartyRegistration
|
||||
.withRegistrationId(REGISTRATION_ID)
|
||||
this.relyingPartyBuilder = RelyingPartyRegistration.withRegistrationId(REGISTRATION_ID)
|
||||
.localEntityIdTemplate(RELYING_PARTY_ENTITY_ID)
|
||||
.providerDetails(c -> c.entityId(ASSERTING_PARTY_ENTITY_ID))
|
||||
.providerDetails(c -> c.webSsoUrl(ASSERTING_PARTY_SSO_URL))
|
||||
@@ -63,8 +67,7 @@ public class DefaultSaml2AuthenticationRequestContextResolverTests {
|
||||
@Test
|
||||
public void resolveWhenRequestAndRelyingPartyNotNullThenCreateSaml2AuthenticationRequestContext() {
|
||||
this.request.addParameter("RelayState", "relay-state");
|
||||
Saml2AuthenticationRequestContext context =
|
||||
this.authenticationRequestContextResolver.resolve(this.request);
|
||||
Saml2AuthenticationRequestContext context = this.authenticationRequestContextResolver.resolve(this.request);
|
||||
|
||||
assertThat(context).isNotNull();
|
||||
assertThat(context.getAssertionConsumerServiceUrl()).isEqualTo(RELYING_PARTY_SSO_URL);
|
||||
@@ -77,20 +80,16 @@ public class DefaultSaml2AuthenticationRequestContextResolverTests {
|
||||
|
||||
@Test
|
||||
public void resolveWhenAssertionConsumerServiceUrlTemplateContainsRegistrationIdThenResolves() {
|
||||
this.relyingPartyBuilder
|
||||
.assertionConsumerServiceLocation("/saml2/authenticate/{registrationId}");
|
||||
Saml2AuthenticationRequestContext context =
|
||||
this.authenticationRequestContextResolver.resolve(this.request);
|
||||
this.relyingPartyBuilder.assertionConsumerServiceLocation("/saml2/authenticate/{registrationId}");
|
||||
Saml2AuthenticationRequestContext context = this.authenticationRequestContextResolver.resolve(this.request);
|
||||
|
||||
assertThat(context.getAssertionConsumerServiceUrl()).isEqualTo("/saml2/authenticate/registration-id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenAssertionConsumerServiceUrlTemplateContainsBaseUrlThenResolves() {
|
||||
this.relyingPartyBuilder
|
||||
.assertionConsumerServiceLocation("{baseUrl}/saml2/authenticate/{registrationId}");
|
||||
Saml2AuthenticationRequestContext context =
|
||||
this.authenticationRequestContextResolver.resolve(this.request);
|
||||
this.relyingPartyBuilder.assertionConsumerServiceLocation("{baseUrl}/saml2/authenticate/{registrationId}");
|
||||
Saml2AuthenticationRequestContext context = this.authenticationRequestContextResolver.resolve(this.request);
|
||||
|
||||
assertThat(context.getAssertionConsumerServiceUrl())
|
||||
.isEqualTo("http://localhost/saml2/authenticate/registration-id");
|
||||
@@ -98,8 +97,8 @@ public class DefaultSaml2AuthenticationRequestContextResolverTests {
|
||||
|
||||
@Test
|
||||
public void resolveWhenRelyingPartyNullThenException() {
|
||||
assertThatCode(() ->
|
||||
this.authenticationRequestContextResolver.resolve(null))
|
||||
assertThatCode(() -> this.authenticationRequestContextResolver.resolve(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-16
@@ -43,6 +43,7 @@ import static org.springframework.security.saml2.provider.service.registration.T
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class Saml2AuthenticationTokenConverterTests {
|
||||
|
||||
@Mock
|
||||
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver;
|
||||
|
||||
@@ -50,8 +51,8 @@ public class Saml2AuthenticationTokenConverterTests {
|
||||
|
||||
@Test
|
||||
public void convertWhenSamlResponseThenToken() {
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter
|
||||
(this.relyingPartyRegistrationResolver);
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
|
||||
this.relyingPartyRegistrationResolver);
|
||||
when(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class)))
|
||||
.thenReturn(this.relyingPartyRegistration);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
@@ -64,8 +65,8 @@ public class Saml2AuthenticationTokenConverterTests {
|
||||
|
||||
@Test
|
||||
public void convertWhenNoSamlResponseThenNull() {
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter
|
||||
(this.relyingPartyRegistrationResolver);
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
|
||||
this.relyingPartyRegistrationResolver);
|
||||
when(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class)))
|
||||
.thenReturn(this.relyingPartyRegistration);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
@@ -74,18 +75,17 @@ public class Saml2AuthenticationTokenConverterTests {
|
||||
|
||||
@Test
|
||||
public void convertWhenNoRelyingPartyRegistrationThenNull() {
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter
|
||||
(this.relyingPartyRegistrationResolver);
|
||||
when(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class)))
|
||||
.thenReturn(null);
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
|
||||
this.relyingPartyRegistrationResolver);
|
||||
when(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))).thenReturn(null);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
assertThat(converter.convert(request)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenGetRequestThenInflates() {
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter
|
||||
(this.relyingPartyRegistrationResolver);
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
|
||||
this.relyingPartyRegistrationResolver);
|
||||
when(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class)))
|
||||
.thenReturn(this.relyingPartyRegistration);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
@@ -101,14 +101,13 @@ public class Saml2AuthenticationTokenConverterTests {
|
||||
|
||||
@Test
|
||||
public void constructorWhenResolverIsNullThenIllegalArgument() {
|
||||
assertThatCode(() -> new Saml2AuthenticationTokenConverter(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> new Saml2AuthenticationTokenConverter(null)).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenUsingSamlUtilsBase64ThenXmlIsValid() throws Exception {
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter
|
||||
(this.relyingPartyRegistrationResolver);
|
||||
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
|
||||
this.relyingPartyRegistrationResolver);
|
||||
when(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class)))
|
||||
.thenReturn(this.relyingPartyRegistration);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
@@ -118,8 +117,7 @@ public class Saml2AuthenticationTokenConverterTests {
|
||||
}
|
||||
|
||||
private void validateSsoCircleXml(String xml) {
|
||||
assertThat(xml)
|
||||
.contains("InResponseTo=\"ARQ9a73ead-7dcf-45a8-89eb-26f3c9900c36\"")
|
||||
assertThat(xml).contains("InResponseTo=\"ARQ9a73ead-7dcf-45a8-89eb-26f3c9900c36\"")
|
||||
.contains(" ID=\"s246d157446618e90e43fb79bdd4d9e9e19cf2c7c4\"")
|
||||
.contains("<saml:Issuer>https://idp.ssocircle.com</saml:Issuer>");
|
||||
}
|
||||
@@ -129,4 +127,5 @@ public class Saml2AuthenticationTokenConverterTests {
|
||||
String response = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
|
||||
return UriUtils.decode(response, UTF_8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-6
@@ -42,18 +42,23 @@ import static org.springframework.security.saml2.provider.service.registration.T
|
||||
public class Saml2MetadataFilterTests {
|
||||
|
||||
RelyingPartyRegistrationRepository repository;
|
||||
|
||||
Saml2MetadataResolver resolver;
|
||||
|
||||
Saml2MetadataFilter filter;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
|
||||
MockHttpServletResponse response;
|
||||
|
||||
FilterChain chain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.repository = mock(RelyingPartyRegistrationRepository.class);
|
||||
this.resolver = mock(Saml2MetadataResolver.class);
|
||||
this.filter = new Saml2MetadataFilter(
|
||||
new DefaultRelyingPartyRegistrationResolver(this.repository), this.resolver);
|
||||
this.filter = new Saml2MetadataFilter(new DefaultRelyingPartyRegistrationResolver(this.repository),
|
||||
this.resolver);
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.chain = mock(FilterChain.class);
|
||||
@@ -103,8 +108,8 @@ public class Saml2MetadataFilterTests {
|
||||
// given
|
||||
this.request.setPathInfo("/saml2/service-provider-metadata/validRegistration");
|
||||
RelyingPartyRegistration validRegistration = noCredentials()
|
||||
.assertingPartyDetails(party -> party
|
||||
.verificationX509Credentials(c -> c.add(relyingPartyVerifyingCredential())))
|
||||
.assertingPartyDetails(
|
||||
party -> party.verificationX509Credentials(c -> c.add(relyingPartyVerifyingCredential())))
|
||||
.build();
|
||||
|
||||
String generatedMetadata = "<xml>test</xml>";
|
||||
@@ -138,7 +143,7 @@ public class Saml2MetadataFilterTests {
|
||||
|
||||
@Test
|
||||
public void setRequestMatcherWhenNullThenIllegalArgument() {
|
||||
assertThatCode(() -> this.filter.setRequestMatcher(null))
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
assertThatCode(() -> this.filter.setRequestMatcher(null)).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user