Skip to content

How to Add a Signature to Service Provider Metadata #13661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sumeetpri opened this issue Aug 18, 2023 · 3 comments
Closed

How to Add a Signature to Service Provider Metadata #13661

sumeetpri opened this issue Aug 18, 2023 · 3 comments
Labels
status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement

Comments

@sumeetpri
Copy link

I'm currently in the process of migrating my application's authentication from Spring Security SAML Extension to Spring Security SAML. I'm using the service provider metadata to register my application with the Identity Provider (IDP). I've managed to generate the metadata for the service provider, but I'm struggling to figure out how to sign the metadata details.

In the previously generated service provider metadata, you can see the presence of the <ds:Signature></ds:Signature> section, which was automatically generated by Spring Security SAML Extension. However, in my migration to Spring Security SAML, I haven't found an implementation for signing the metadata in the OpenSamlMetadataResolver.

Here's a snippet of my code:

SecurityFilterChain configure(HttpSecurity http) throws Exception {
    OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider();

    Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationRepository,
        new OpenSamlMetadataResolver());
    http.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);

    http.authorizeHttpRequests(requests -> requests
        .requestMatchers("/saml2/service-provider-metadata/**")
        .permitAll()
    ).saml2Login((saml2) -> saml2.loginProcessingUrl(SAML2_ASSERTION_CONSUMER_SERVICE_URL))
    .build();
}

The service provider metadata generated by Spring Security SAML Extension includes a <ds:Signature> section as follows:

<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="example.com" entityID="example.com">
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <!-- Signature details here -->
    </ds:Signature>
    <!-- Other metadata details -->
</md:EntityDescriptor>

My question is, how can I achieve the same feature of generating and adding the <ds:Signature> section in the service provider metadata using Spring Security SAML?

I've already reviewed the OpenSamlMetadataResolver implementation, but I couldn't find a built-in way to sign the metadata. Any guidance or code examples on how to achieve this would be greatly appreciated.

@sumeetpri sumeetpri added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Aug 18, 2023
@sumeetpri
Copy link
Author

I am able to add signature , so closing this open issue .

@arotondo
Copy link

arotondo commented Apr 5, 2024

@sumeetpri, that is great news. Can you please share how you added the signature? We are facing the same problem and adding the signature does not seem to be trivial.

@longgt
Copy link

longgt commented May 2, 2024

Regarding to Signing with OpenSAML, we need 3 steps to
add a Signature to Service Provider Metadata, like Spring Security Saml Extension did.

The default metadata resolver of Spring Security SAML2 org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver is missing the action at step 3 (calling Signer.signObject) so the final hash will not be computed properly although we did set a valid Signature object.

The below is 3 steps based on the source of Spring Security 6.2.2

Step 1. Create a Signature
We can use the below for referencing how to create Signature from RelyingPartyRegistration

Step 2. Add Signature to EntityDescriptor of SP Provider
OpenSamlMetadataResolver has a property with name entityDescriptorCustomizer, we can use it for adding custom logic before serializing it to XML.

OpenSamlMetadataResolver metadataResolver = new OpenSamlMetadataResolver();
metadataResolver.setEntityDescriptorCustomizer(parameters -> {
    SignatureSigningParameters signingParameters = resolveSigningParameters(parameters.getRelyingPartyRegistration());
    try {
        SignatureSupport.prepareSignatureParams(signature, signingParameters);
        parameters.getEntityDescriptor().setSignature(signature);
     } catch (SecurityException e) {
        throw new Saml2Exception(e);
     }
});

Step 3. Call Signer.signObject to compute the final hash
The magic is here
Since Spring Security SAML2 allows us customizing OpenSAML configuration, we can register a custom marshaller for EntityDescriptor. This custom logic allows us calling Signer.signObject right after EntityDescriptor has been serialized into XML successfully.

    static {
        OpenSamlInitializationService.requireInitialize(factory -> {
            factory.getMarshallerFactory().registerMarshaller(EntityDescriptor.DEFAULT_ELEMENT_NAME,
                    new CustomEntityDescriptorMarshaller());
        });
    }

This is the sample demonstrating how to custom it

public class CustomEntityDescriptorMarshaller extends EntityDescriptorMarshaller {
    /** {@inheritDoc} */
    public Element marshall(final XMLObject xmlObject, final Document document) throws MarshallingException {
        Element result = super.marshall(xmlObject, document);
        // Custom logic here
        signObject(xmlObject);

        return result;
    }

    /** {@inheritDoc} */
    public Element marshall(final XMLObject xmlObject, final Element parentElement) throws MarshallingException {
        Element result = super.marshall(xmlObject, parentElement);
        // Custom logic here
        signObject(xmlObject);

        return result;
    }

    protected void signObject(final XMLObject xmlObject) {
        if (!(xmlObject instanceof SignableXMLObject)) {
            return;
        }
        SignableXMLObject signable = (SignableXMLObject) xmlObject;

        if (signable.getSignature() != null) {
            try {
                Signer.signObject(signable.getSignature());
            } catch (SignatureException e) {
                throw new Saml2Exception(e);
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants