Add support for SAML2 relying party registration's decryption credentials

Closes gh-23705
pull/23914/head
Stephane Nicoll 4 years ago
parent 10f887a5ad
commit 9ab3abb728

@ -63,6 +63,8 @@ public class Saml2RelyingPartyProperties {
private final Signing signing = new Signing();
private final Decryption decryption = new Decryption();
/**
* Remote SAML Identity Provider.
*/
@ -84,6 +86,10 @@ public class Saml2RelyingPartyProperties {
return this.signing;
}
public Decryption getDecryption() {
return this.decryption;
}
public Identityprovider getIdentityprovider() {
return this.identityprovider;
}
@ -123,8 +129,7 @@ public class Saml2RelyingPartyProperties {
public static class Signing {
/**
* Credentials used for signing and decrypting the SAML authentication
* request.
* Credentials used for signing the SAML authentication request.
*/
private List<Credential> credentials = new ArrayList<>();
@ -139,7 +144,7 @@ public class Saml2RelyingPartyProperties {
public static class Credential {
/**
* Private key used for signing or decrypting.
* Private key used for signing.
*/
private Resource privateKeyLocation;
@ -170,6 +175,53 @@ public class Saml2RelyingPartyProperties {
}
public static class Decryption {
/**
* Credentials used for decrypting the SAML authentication request.
*/
private List<Credential> credentials = new ArrayList<>();
public List<Credential> getCredentials() {
return this.credentials;
}
public void setCredentials(List<Credential> credentials) {
this.credentials = credentials;
}
public static class Credential {
/**
* Private key used for decrypting.
*/
private Resource privateKeyLocation;
/**
* Relying Party X509Certificate shared with the identity provider.
*/
private Resource certificateLocation;
public Resource getPrivateKeyLocation() {
return this.privateKeyLocation;
}
public void setPrivateKeyLocation(Resource privateKey) {
this.privateKeyLocation = privateKey;
}
public Resource getCertificateLocation() {
return this.certificateLocation;
}
public void setCertificateLocation(Resource certificate) {
this.certificateLocation = certificate;
}
}
}
/**
* Represents a remote Identity Provider.
*/

@ -26,6 +26,7 @@ import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Decryption;
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Identityprovider.Verification;
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Registration;
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Registration.Signing;
@ -36,6 +37,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.security.converter.RsaKeyConverters;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails;
@ -78,6 +80,8 @@ class Saml2RelyingPartyRegistrationConfiguration {
builder.assertingPartyDetails(mapIdentityProvider(properties, usingMetadata));
builder.signingX509Credentials((credentials) -> properties.getSigning().getCredentials().stream()
.map(this::asSigningCredential).forEach(credentials::add));
builder.decryptionX509Credentials((credentials) -> properties.getDecryption().getCredentials().stream()
.map(this::asDecryptionCredential).forEach(credentials::add));
builder.assertingPartyDetails((details) -> details
.verificationX509Credentials((credentials) -> properties.getIdentityprovider().getVerification()
.getCredentials().stream().map(this::asVerificationCredential).forEach(credentials::add)));
@ -111,8 +115,13 @@ class Saml2RelyingPartyRegistrationConfiguration {
private Saml2X509Credential asSigningCredential(Signing.Credential properties) {
RSAPrivateKey privateKey = readPrivateKey(properties.getPrivateKeyLocation());
X509Certificate certificate = readCertificate(properties.getCertificateLocation());
return new Saml2X509Credential(privateKey, certificate, Saml2X509Credential.Saml2X509CredentialType.SIGNING,
Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
return new Saml2X509Credential(privateKey, certificate, Saml2X509CredentialType.SIGNING);
}
private Saml2X509Credential asDecryptionCredential(Decryption.Credential properties) {
RSAPrivateKey privateKey = readPrivateKey(properties.getPrivateKeyLocation());
X509Certificate certificate = readCertificate(properties.getCertificateLocation());
return new Saml2X509Credential(privateKey, certificate, Saml2X509CredentialType.DECRYPTION);
}
private Saml2X509Credential asVerificationCredential(Verification.Credential properties) {

@ -98,7 +98,8 @@ class Saml2RelyingPartyAutoConfigurationTests {
assertThat(registration.getAssertingPartyDetails().getSingleSignOnServiceBinding())
.isEqualTo(Saml2MessageBinding.POST);
assertThat(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()).isEqualTo(false);
assertThat(registration.getSigningX509Credentials()).isNotNull();
assertThat(registration.getSigningX509Credentials()).hasSize(1);
assertThat(registration.getDecryptionX509Credentials()).hasSize(1);
assertThat(registration.getAssertingPartyDetails().getVerificationX509Credentials()).isNotNull();
assertThat(registration.getEntityId()).isEqualTo("{baseUrl}/saml2/foo-entity-id");
});
@ -182,6 +183,8 @@ class Saml2RelyingPartyAutoConfigurationTests {
return new String[] {
PREFIX + ".foo.signing.credentials[0].private-key-location=classpath:saml/private-key-location",
PREFIX + ".foo.signing.credentials[0].certificate-location=classpath:saml/certificate-location",
PREFIX + ".foo.decryption.credentials[0].private-key-location=classpath:saml/private-key-location",
PREFIX + ".foo.decryption.credentials[0].certificate-location=classpath:saml/certificate-location",
PREFIX + ".foo.identityprovider.singlesignon.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php",
PREFIX + ".foo.identityprovider.singlesignon.binding=post",
PREFIX + ".foo.identityprovider.singlesignon.sign-request=false",

@ -3866,7 +3866,12 @@ You can register multiple relying parties under the `spring.security.saml2.relyi
relyingparty:
registration:
my-relying-party1:
signing.credentials:
signing:
credentials:
- private-key-location: "path-to-private-key"
certificate-location: "path-to-certificate"
decryption:
credentials:
- private-key-location: "path-to-private-key"
certificate-location: "path-to-certificate"
identityprovider:
@ -3875,12 +3880,15 @@ You can register multiple relying parties under the `spring.security.saml2.relyi
- certificate-location: "path-to-verification-cert"
entity-id: "remote-idp-entity-id1"
sso-url: "https://remoteidp1.sso.url"
my-relying-party2:
signing:
credentials:
- private-key-location: "path-to-private-key"
certificate-location: "path-to-certificate"
decryption:
credentials:
- private-key-location: "path-to-private-key"
certificate-location: "path-to-certificate"
identityprovider:
verification:
credentials:

Loading…
Cancel
Save