diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyProperties.java index 43ad78f5b6f..dc49c2dd652 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyProperties.java @@ -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 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 credentials = new ArrayList<>(); + + public List getCredentials() { + return this.credentials; + } + + public void setCredentials(List 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. */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java index 59af2c3b10b..4ebe6876922 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java @@ -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) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java index 2361eb4b03f..f063c37faaf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java @@ -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", diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index 2ba625e4463..026d64c0cfd 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -3866,21 +3866,29 @@ You can register multiple relying parties under the `spring.security.saml2.relyi relyingparty: registration: my-relying-party1: - signing.credentials: - - private-key-location: "path-to-private-key" - certificate-location: "path-to-certificate" + 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: - 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: