Skip to content
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

RelyingPartyRegistrations typically produces unusable registrationId #15017

Open
OrangeDog opened this issue May 7, 2024 · 5 comments
Open
Assignees
Labels
in: saml2 An issue in SAML2 modules type: enhancement A general enhancement
Milestone

Comments

@OrangeDog
Copy link
Contributor

Describe the bug
Methods such as RelyingPartyRegistrations.collectionFromMetadataLocation use the entity of the asserting party as the registrationId.

SAML entity IDs are usually URIs (and often a URL to their metadata), and Spring's SAML support (incl. the default login page) requires the registrationId to be added to a URL.

This typically results in an error when trying to access e.g. https://relyingparty.com/saml2/authenticate/https://assertingparty.com/SAML/metadata.xml

To Reproduce
Construct a RelyingPartyRegistrationRepository using RelyingPartyRegistrations without changing the default registrationId.

Expected behavior
registrationId should always be generated as URL-safe, or should always be escaped when used in a URL.

Workaround

List<RelyingPartyRegistration> registrations = RelyingPartyRegistrations.collectionFromMetadataLocation(url)
        .stream()
        .map(builder -> builder
                .entityId("https://relyingparty.com/saml-metadata.xml")
                // etc.
                .build())
        .map(reg -> reg.mutate()
                .registrationId(reg.getAssertingPartyDetails().getEntityId().replaceAll("[:/?#]+", "_"))
                .build())
        .toList();

Caveat
Using URLEncoder.encode to make it safe is not sufficient, as you still get a 400 Bad Request from a default Spring Boot server.

@OrangeDog OrangeDog added status: waiting-for-triage An issue we've not yet triaged type: bug A general bug labels May 7, 2024
@sjohnr sjohnr added the in: saml2 An issue in SAML2 modules label May 9, 2024
@jzheaux
Copy link
Contributor

jzheaux commented May 20, 2024

Thanks, @OrangeDog, for the suggestion. Note that this is covered in the JavaDoc:

* Note that by default the registrationId is set to be the given metadata location,
* but this will most often not be sufficient. To complete the configuration, most
* applications will also need to provide a registrationId, like so:

Still, I think this would be good to investigate and improve. I wanted to add this context so it's clear why I'm changing the ticket to an enhancement.

Using URLEncoder.encode to make it safe is not sufficient, as you still get a 400 Bad Request from a default Spring Boot server.

Hex encoding might be worth considering.

@jzheaux jzheaux added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged type: bug A general bug labels May 20, 2024
@jzheaux jzheaux added this to the 6.4.x milestone May 20, 2024
@OrangeDog
Copy link
Contributor Author

The SAML Discovery protocol (which the previous extension implemented) uses a query parameter rather than a path fragment so that entity ids can be transferred safely. Is it possible to do that with the current authenticationRequestUri template? A standard URI encoding would work there.

@jzheaux
Copy link
Contributor

jzheaux commented May 23, 2024

Nice idea. That's not yet supported in the DSL, but you could achieve that by publishing the Saml2WebSsoAuthenticationRequestFilter in the filter chain and setting the RequestMatcher accordingly.

That said, the Spring Security RequestMatcher implementations don't match the query string. So to simplify that, we could add some internal logic to the DSL so folks can do:

saml2Login((saml2) -> saml2
    .authenticationRequestUri("/saml2/authenticate?entityID={registrationId}")

or similar.

@OrangeDog
Copy link
Contributor Author

publishing the Saml2WebSsoAuthenticationRequestFilter in the filter chain and setting the RequestMatcher accordingly

That doesn't seem right. Surely right now you have to build and supply a Saml2AuthenticationRequestResolver to the DSL?

@OrangeDog
Copy link
Contributor Author

Noting that something like this works great, falling through to the login page nicely to choose a registration.

@Override
public MatchResult matcher(HttpServletRequest request) {
    String registrationId = request.getParameter("registrationId");
    if (new AntPathRequestMatcher("/login").matches(request) && StringUtils.hasText(registrationId)) {
        return MatchResult.match(Map.of("registrationId", registrationId));
    } else {
        return MatchResult.notMatch();
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: saml2 An issue in SAML2 modules type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants