|
|
|
|
@@ -40,6 +40,7 @@ import org.springframework.context.annotation.Bean;
|
|
|
|
|
import org.springframework.context.annotation.Conditional;
|
|
|
|
|
import org.springframework.context.annotation.Configuration;
|
|
|
|
|
import org.springframework.core.io.Resource;
|
|
|
|
|
import org.springframework.core.log.LogMessage;
|
|
|
|
|
import org.springframework.security.converter.RsaKeyConverters;
|
|
|
|
|
import org.springframework.security.saml2.core.Saml2X509Credential;
|
|
|
|
|
import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;
|
|
|
|
|
@@ -49,6 +50,7 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP
|
|
|
|
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.Builder;
|
|
|
|
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
|
|
|
|
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;
|
|
|
|
|
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
|
|
|
|
|
import org.springframework.util.Assert;
|
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
|
|
|
|
|
@@ -58,6 +60,7 @@ import org.springframework.util.StringUtils;
|
|
|
|
|
*
|
|
|
|
|
* @author Madhura Bhave
|
|
|
|
|
* @author Phillip Webb
|
|
|
|
|
* @author Moritz Halbritter
|
|
|
|
|
*/
|
|
|
|
|
@Configuration(proxyBeanMethods = false)
|
|
|
|
|
@Conditional(RegistrationConfiguredCondition.class)
|
|
|
|
|
@@ -78,12 +81,11 @@ class Saml2RelyingPartyRegistrationConfiguration {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private RelyingPartyRegistration asRegistration(String id, Registration properties) {
|
|
|
|
|
boolean usingMetadata = StringUtils
|
|
|
|
|
.hasText(getFromAssertingParty(properties, id, "metadata-uri", AssertingParty::getMetadataUri));
|
|
|
|
|
Builder builder = (usingMetadata) ? RelyingPartyRegistrations
|
|
|
|
|
.fromMetadataLocation(
|
|
|
|
|
getFromAssertingParty(properties, id, "metadata-uri", AssertingParty::getMetadataUri))
|
|
|
|
|
.registrationId(id) : RelyingPartyRegistration.withRegistrationId(id);
|
|
|
|
|
AssertingPartyProperties assertingParty = new AssertingPartyProperties(properties, id);
|
|
|
|
|
boolean usingMetadata = StringUtils.hasText(assertingParty.getMetadataUri());
|
|
|
|
|
Builder builder = (usingMetadata)
|
|
|
|
|
? RelyingPartyRegistrations.fromMetadataLocation(assertingParty.getMetadataUri()).registrationId(id)
|
|
|
|
|
: RelyingPartyRegistration.withRegistrationId(id);
|
|
|
|
|
builder.assertionConsumerServiceLocation(properties.getAcs().getLocation());
|
|
|
|
|
builder.assertionConsumerServiceBinding(properties.getAcs().getBinding());
|
|
|
|
|
builder.assertingPartyDetails(mapAssertingParty(properties, id, usingMetadata));
|
|
|
|
|
@@ -91,8 +93,8 @@ class Saml2RelyingPartyRegistrationConfiguration {
|
|
|
|
|
.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) -> getFromAssertingParty(properties, id, "verification", AssertingParty::getVerification)
|
|
|
|
|
builder.assertingPartyDetails(
|
|
|
|
|
(details) -> details.verificationX509Credentials((credentials) -> assertingParty.getVerification()
|
|
|
|
|
.getCredentials().stream().map(this::asVerificationCredential).forEach(credentials::add)));
|
|
|
|
|
builder.entityId(properties.getEntityId());
|
|
|
|
|
RelyingPartyRegistration registration = builder.build();
|
|
|
|
|
@@ -101,35 +103,15 @@ class Saml2RelyingPartyRegistrationConfiguration {
|
|
|
|
|
return registration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("deprecation")
|
|
|
|
|
private <T> T getFromAssertingParty(Registration registration, String id, String name,
|
|
|
|
|
Function<AssertingParty, T> getter) {
|
|
|
|
|
T newValue = getter.apply(registration.getAssertingParty());
|
|
|
|
|
if (newValue != null) {
|
|
|
|
|
return newValue;
|
|
|
|
|
}
|
|
|
|
|
T deprecatedValue = getter.apply(registration.getIdentityprovider());
|
|
|
|
|
if (deprecatedValue != null) {
|
|
|
|
|
logger.warn(String.format(
|
|
|
|
|
"Property 'spring.security.saml2.relyingparty.registration.identityprovider.%1$s.%2$s' is deprecated, please use 'spring.security.saml2.relyingparty.registration.asserting-party.%1$s.%2$s' instead",
|
|
|
|
|
id, name));
|
|
|
|
|
return deprecatedValue;
|
|
|
|
|
}
|
|
|
|
|
return newValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Consumer<AssertingPartyDetails.Builder> mapAssertingParty(Registration registration, String id,
|
|
|
|
|
boolean usingMetadata) {
|
|
|
|
|
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
|
|
|
|
return (details) -> {
|
|
|
|
|
map.from(() -> getFromAssertingParty(registration, id, "entity-id", AssertingParty::getEntityId))
|
|
|
|
|
.to(details::entityId);
|
|
|
|
|
map.from(() -> getFromAssertingParty(registration, id, "singlesignon.binding",
|
|
|
|
|
(property) -> property.getSinglesignon().getBinding())).to(details::singleSignOnServiceBinding);
|
|
|
|
|
map.from(() -> getFromAssertingParty(registration, id, "singlesignon.url",
|
|
|
|
|
(property) -> property.getSinglesignon().getUrl())).to(details::singleSignOnServiceLocation);
|
|
|
|
|
map.from(() -> getFromAssertingParty(registration, id, "singlesignon.sign-request",
|
|
|
|
|
(property) -> property.getSinglesignon().getSignRequest())).when((ignored) -> !usingMetadata)
|
|
|
|
|
AssertingPartyProperties assertingParty = new AssertingPartyProperties(registration, id);
|
|
|
|
|
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
|
|
|
|
map.from(assertingParty::getEntityId).to(details::entityId);
|
|
|
|
|
map.from(assertingParty::getSingleSignonBinding).to(details::singleSignOnServiceBinding);
|
|
|
|
|
map.from(assertingParty::getSingleSignonUrl).to(details::singleSignOnServiceLocation);
|
|
|
|
|
map.from(assertingParty::getSingleSignonSignRequest).when((ignored) -> !usingMetadata)
|
|
|
|
|
.to(details::wantAuthnRequestsSigned);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
@@ -181,4 +163,61 @@ class Saml2RelyingPartyRegistrationConfiguration {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Access to {@link AssertingParty} properties taking into account deprecations.
|
|
|
|
|
*/
|
|
|
|
|
private static class AssertingPartyProperties {
|
|
|
|
|
|
|
|
|
|
private final Registration registration;
|
|
|
|
|
|
|
|
|
|
private final String id;
|
|
|
|
|
|
|
|
|
|
AssertingPartyProperties(Registration registration, String id) {
|
|
|
|
|
this.registration = registration;
|
|
|
|
|
this.id = id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String getMetadataUri() {
|
|
|
|
|
return get("metadata-uri", AssertingParty::getMetadataUri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Verification getVerification() {
|
|
|
|
|
return get("verification", AssertingParty::getVerification);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String getEntityId() {
|
|
|
|
|
return get("entity-id", AssertingParty::getEntityId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Saml2MessageBinding getSingleSignonBinding() {
|
|
|
|
|
return get("singlesignon.binding", (property) -> property.getSinglesignon().getBinding());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String getSingleSignonUrl() {
|
|
|
|
|
return get("singlesignon.url", (property) -> property.getSinglesignon().getUrl());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Boolean getSingleSignonSignRequest() {
|
|
|
|
|
return get("singlesignon.sign-request", (property) -> property.getSinglesignon().getSignRequest());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("deprecation")
|
|
|
|
|
private <T> T get(String name, Function<AssertingParty, T> getter) {
|
|
|
|
|
T newValue = getter.apply(this.registration.getAssertingParty());
|
|
|
|
|
if (newValue != null) {
|
|
|
|
|
return newValue;
|
|
|
|
|
}
|
|
|
|
|
T deprecatedValue = getter.apply(this.registration.getIdentityprovider());
|
|
|
|
|
if (deprecatedValue != null) {
|
|
|
|
|
logger.warn(LogMessage.format(
|
|
|
|
|
"Property 'spring.security.saml2.relyingparty.registration.identityprovider.%1$s.%2$s' is deprecated, "
|
|
|
|
|
+ "please use 'spring.security.saml2.relyingparty.registration.asserting-party.%1$s.%2$s' instead",
|
|
|
|
|
this.id, name));
|
|
|
|
|
return deprecatedValue;
|
|
|
|
|
}
|
|
|
|
|
return newValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|