Skip to content

Customizing the metadata endpoint does not work #9133

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
dawi opened this issue Oct 15, 2020 · 6 comments
Closed

Customizing the metadata endpoint does not work #9133

dawi opened this issue Oct 15, 2020 · 6 comments
Assignees
Labels
in: docs An issue in Documentation or samples status: backported An issue that has been backported to maintenance branches type: bug A general bug
Milestone

Comments

@dawi
Copy link

dawi commented Oct 15, 2020

Describe the bug

The documentation states that the metadata endpoint can be changed by like this:

filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata", "GET"));

But it does not work as expected because the registration id resolver returns metadata as registration id due to the used ant matcher.

private final RequestMatcher requestMatcher = new AntPathRequestMatcher("/**/{registrationId}");

@dawi dawi added status: waiting-for-triage An issue we've not yet triaged type: bug A general bug labels Oct 15, 2020
@jzheaux
Copy link
Contributor

jzheaux commented Oct 16, 2020

Thanks, @dawi, for the report. I think we should update the documentation.

The filter by default expects the registrationId to be part of the URL. For example, you can customize the URL like so:

filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET"));

Would you be able to provide a PR updating the documentation?

@jzheaux jzheaux self-assigned this Oct 16, 2020
@jzheaux jzheaux added in: docs An issue in Documentation or samples and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 16, 2020
@jzheaux jzheaux added this to the 5.5.0-M1 milestone Oct 16, 2020
@dawi
Copy link
Author

dawi commented Oct 18, 2020

Requiring the registrationId as part of the metadata URL would prevent transparent upgrades from spring-security-saml for those who have a metadata URL without registrationId, which seems to be the default there.

I understand that registrationId is required as part of the metadata URL if there are multiple RelyingPartyRegistrations in an application. But if there is only one, wouldn't it make sense to allow to omit it?

Update: I have found a really hacky workaround: One could use "metadata" as registrationId and then use "/saml2/{registrationId}" as AntPathRequestMatcher pattern. But I don't like it and I'm sure nobody want's that. :)

Update 2: If a custom RelyingPartyRegistrationRepository only holds a single RelyingPartyRegistration and the findByRegistrationId(String registrationId) method always returns that instance, then it is also possible to omit the registrationId because the name does not matter in this case. So from a user perspective this would be the way to go, although it feels like it only works as a side effect.

@dawi
Copy link
Author

dawi commented Oct 27, 2020

Another thing I don't understand is that currently the URL should contain a registrationId placeholder like this:

filter.setRequestMatcher(new AntPathRequestMatcher("/saml2/metadata/{registrationId}", "GET"));

but this pattern seems not to be used to parse the registrationId in Saml2MetadataFilter.
Instead the registrationId is parsed via RegistrationIdResolver in DefaultRelyingPartyRegistrationResolver which uses the non configurable URL pattern /**/{registrationId}.

So if someone want's to set a metadata url like /saml2/{registrationId}/metadata it would not work.

All in all, it would be nice if it could be simpler to configure the metadata url.

If spring security could offer such a solution, then maybe spring boot would adopt this too, and the metadata URL could also be configured via application.yml.

@jgrandja jgrandja modified the milestones: 5.5.0-M1, 5.5.0-M2 Nov 3, 2020
@jzheaux
Copy link
Contributor

jzheaux commented Nov 3, 2020

All in all, it would be nice if it could be simpler to configure the metadata URL.

Do you have a proposal for how to make things simpler?

If a custom RelyingPartyRegistrationRepository only holds a single RelyingPartyRegistration and the findByRegistrationId(String registrationId) method always returns that instance, then it is also possible to omit the registrationId because the name does not matter in this case. So from a user perspective this would be the way to go, although it feels like it only works as a side effect.

The repository's API is intended to be reduceable to a single-tenant application, it's not a "happy accident".

In your situation, I see two possibilities:

  • First, introduce a rewrite rule so that the old URL points to the new one.
  • Second, rely on the fact that RelyingPartyRegistrationRepository always returns the same registration

There may be ways to simplify this as well for the other scenarios you outlined, and I'm open to your thoughts. Most things are private in DefaultRelyingPartyRegistrationResolver which gives us a lot of flexibility to change it.

@jzheaux
Copy link
Contributor

jzheaux commented Dec 2, 2020

For the single-tenant scenario, you can replace the default resolver with a lambda, like so:

@Bean 
Filter metadata(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
    Saml2MetadataFilter metadata = new Saml2MetadataFilter(
        (request) -> relyingPartyRegistrationRepository.findByRegistrationId("single"),
        new OpenSamlMetadataResolver());
    metadata.setRequestMatcher(new AntMathRequestMatcher("/saml2/metadata", "GET"));
    return metadata;
}

This is about the same level of simplicity as the default Saml2MetadataFilter arrangement:

@Bean 
Filter metadata(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
    Saml2MetadataFilter metadata = new Saml2MetadataFilter(
        new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository),
        new OpenSamlMetadataResolver());
    return metadata;
}

For multi-tenant scenarios, it's important to remember that a path matcher may be used to both identify endpoints as well as resolve registration ids, but it's not required. The way to figure out the registration id may be completely different (for example, by subdomain). Any application can use a custom Converter<HttpServletRequest, RelyingPartyRegistration> to address that.

As reports of more use cases come in, I think improvements to DefaultRelyingPartyRegistrationResolver as an alternative to customization will become clearer. Until then, I'm inclined to leave it as-is.

I think the best step forward right now is to clarify the documentation.

@jzheaux jzheaux closed this as completed in fe93326 Dec 2, 2020
jzheaux added a commit that referenced this issue Dec 2, 2020
@dawi
Copy link
Author

dawi commented Dec 2, 2020

I think you are right. In retrospect, it is quite easy to configure, and yet very flexible.
For now, updating the docs would probably be the best thing to do. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: docs An issue in Documentation or samples status: backported An issue that has been backported to maintenance branches type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants