From 7678523b730eb55bed8e88fda013a88c6f270b6c Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Thu, 9 Mar 2023 09:32:58 -0700 Subject: [PATCH] Support Creating EntitiesDescriptor Clsoes gh-12844 --- .../metadata/OpenSamlMetadataResolver.java | 47 ++++++++++++++++--- .../metadata/Saml2MetadataResolver.java | 4 ++ .../OpenSamlMetadataResolverTests.java | 19 ++++++++ 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolver.java index 4e0ad7f6a2..45fb14567a 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolver.java @@ -30,11 +30,13 @@ import org.opensaml.core.xml.XMLObjectBuilder; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.opensaml.saml.saml2.metadata.KeyDescriptor; import org.opensaml.saml.saml2.metadata.NameIDFormat; import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml.saml2.metadata.impl.EntitiesDescriptorMarshaller; import org.opensaml.saml.saml2.metadata.impl.EntityDescriptorMarshaller; import org.opensaml.security.credential.UsageType; import org.opensaml.xmlsec.signature.KeyInfo; @@ -65,6 +67,8 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver { private final EntityDescriptorMarshaller entityDescriptorMarshaller; + private final EntitiesDescriptorMarshaller entitiesDescriptorMarshaller; + private Consumer entityDescriptorCustomizer = (parameters) -> { }; @@ -72,19 +76,40 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver { this.entityDescriptorMarshaller = (EntityDescriptorMarshaller) XMLObjectProviderRegistrySupport .getMarshallerFactory().getMarshaller(EntityDescriptor.DEFAULT_ELEMENT_NAME); Assert.notNull(this.entityDescriptorMarshaller, "entityDescriptorMarshaller cannot be null"); + this.entitiesDescriptorMarshaller = (EntitiesDescriptorMarshaller) XMLObjectProviderRegistrySupport + .getMarshallerFactory().getMarshaller(EntitiesDescriptor.DEFAULT_ELEMENT_NAME); + Assert.notNull(this.entitiesDescriptorMarshaller, "entitiesDescriptorMarshaller cannot be null"); } @Override public String resolve(RelyingPartyRegistration relyingPartyRegistration) { - EntityDescriptor entityDescriptor = build(EntityDescriptor.DEFAULT_ELEMENT_NAME); - entityDescriptor.setEntityID(relyingPartyRegistration.getEntityId()); - SPSSODescriptor spSsoDescriptor = buildSpSsoDescriptor(relyingPartyRegistration); - entityDescriptor.getRoleDescriptors(SPSSODescriptor.DEFAULT_ELEMENT_NAME).add(spSsoDescriptor); - this.entityDescriptorCustomizer - .accept(new EntityDescriptorParameters(entityDescriptor, relyingPartyRegistration)); + EntityDescriptor entityDescriptor = entityDescriptor(relyingPartyRegistration); return serialize(entityDescriptor); } + public String resolve(Iterable relyingPartyRegistrations) { + Collection entityDescriptors = new ArrayList<>(); + for (RelyingPartyRegistration registration : relyingPartyRegistrations) { + EntityDescriptor entityDescriptor = entityDescriptor(registration); + entityDescriptors.add(entityDescriptor); + } + if (entityDescriptors.size() == 1) { + return serialize(entityDescriptors.iterator().next()); + } + EntitiesDescriptor entities = build(EntitiesDescriptor.DEFAULT_ELEMENT_NAME); + entities.getEntityDescriptors().addAll(entityDescriptors); + return serialize(entities); + } + + private EntityDescriptor entityDescriptor(RelyingPartyRegistration registration) { + EntityDescriptor entityDescriptor = build(EntityDescriptor.DEFAULT_ELEMENT_NAME); + entityDescriptor.setEntityID(registration.getEntityId()); + SPSSODescriptor spSsoDescriptor = buildSpSsoDescriptor(registration); + entityDescriptor.getRoleDescriptors(SPSSODescriptor.DEFAULT_ELEMENT_NAME).add(spSsoDescriptor); + this.entityDescriptorCustomizer.accept(new EntityDescriptorParameters(entityDescriptor, registration)); + return entityDescriptor; + } + /** * Set a {@link Consumer} for modifying the OpenSAML {@link EntityDescriptor} * @param entityDescriptorCustomizer a consumer that accepts an @@ -184,6 +209,16 @@ public final class OpenSamlMetadataResolver implements Saml2MetadataResolver { } } + private String serialize(EntitiesDescriptor entities) { + try { + Element element = this.entitiesDescriptorMarshaller.marshall(entities); + return SerializeSupport.prettyPrintXML(element); + } + catch (Exception ex) { + throw new Saml2Exception(ex); + } + } + /** * A tuple containing an OpenSAML {@link EntityDescriptor} and its associated * {@link RelyingPartyRegistration} diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/Saml2MetadataResolver.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/Saml2MetadataResolver.java index 999a124771..c8fa5c60f4 100644 --- a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/Saml2MetadataResolver.java +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/metadata/Saml2MetadataResolver.java @@ -35,4 +35,8 @@ public interface Saml2MetadataResolver { */ String resolve(RelyingPartyRegistration relyingPartyRegistration); + default String resolve(Iterable relyingPartyRegistrations) { + return resolve(relyingPartyRegistrations.iterator().next()); + } + } diff --git a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolverTests.java b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolverTests.java index 0d75992cd8..78f5f560b7 100644 --- a/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolverTests.java +++ b/saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/metadata/OpenSamlMetadataResolverTests.java @@ -16,6 +16,8 @@ package org.springframework.security.saml2.provider.service.metadata; +import java.util.List; + import org.junit.jupiter.api.Test; import org.springframework.security.saml2.core.TestSaml2X509Credentials; @@ -89,4 +91,21 @@ public class OpenSamlMetadataResolverTests { assertThat(metadata).contains("") + .contains("") + .contains("MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBh") + .contains("Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\"") + .contains("Location=\"https://rp.example.org/acs\" index=\"1\"") + .contains("ResponseLocation=\"https://rp.example.org/logout/saml2/response\""); + } + }