There are are number of higher-level SAML 2.0 components that derive the registration id from the request. Examples include Saml2MetadataFilter, Saml2WebSsoAuthenticationFilter, and Saml2WebSsoAuthenticationRequestFilter, with more to come in the future.
On each request, RelyingPartyRegistrationResolver re-derives the registration id and usually needs to use an equivalent strategy. This complexifies some use cases since it then requires the derivation strategy in the resolver to sync up with the strategy in the higher-level component.
For example, by default the SAML 2.0 Response endpoint is configured to be /login/saml2/sso/{registrationId} in Saml2WebSsoAuthenticationFilter. Since the default resolver only takes an HttpServletRequest as a parameter, the resolver must re-perform the same request-matching logic in order to derive the registrationId for its purposes. Aside from the duplication of effort, this also means that if the application wants to customize the URL to be /{registrationId}/login/saml2/sso, for example, then it needs to be configured in both places.
Like OAuth2AuthorizationRequestResolver, these resolvers should allow higher-level components to specify the registration id when they have it, alleviating this duplication of effort.
Likely this will require introducing an interface, which should be named RelyingPartyRegistrationResolver. Components that use the Converter<HttpServletRequest, RelyingPartyRegistration> should adapt to this interface and should send any registration id that they have.
Comment From: jzheaux
Related to https://github.com/spring-projects/spring-security/issues/9133
Comment From: jzheaux
The original impetus for this ticket is #8731 and since it has been reopened for additional research, we'll reopen this one as well, just in case changes there require changes here.
Comment From: jzheaux
The introduction of this interface breaks passivity in a fairly isolated way.
If an application constructs a Saml2MetadataFilter like so:
Converter<HttpServletRequest, RelyingPartyRegistration> registrationResolver =
new DefaultRelyingPartyRegistrationResolver(registrations);
Saml2MetadataResolver metadataResolver = myMetadataResolver();
Saml2MetadataFilter filter = new Saml2MetadataFilter(registrationResolver, metadataResolver);
Then there will be no issue when updating to the latest.
However, if the construction of DefaultRelyingPartyRegistrationResolver is inlined:
Saml2MetadataResolver metadataResolver = myMetadataResolver();
Saml2MetadataFilter filter = new Saml2MetadataFilter(
new DefaultRelyingPartyRegistrationResolver(registrations),
metadataResolver);
Then which constructor to be used is ambiguous since DefaultRelyingPartyRegistrationResolver implements both Converter<HttpServletRequest, RelyingPartyRegistration> and RelyingPartyRegistrationResolver.
The resolution is to place the construction of DefaultRelyingPartyRegistrationResolver onto its own line like so:
RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(registrations)
Saml2MetadataResolver metadataResolver = myMetadataResolver();
Saml2MetadataFilter filter = new Saml2MetadataFilter(registrationResolver, metadataResolver);