Description
Similar to OAuth2AuthenticationRequestResolver
, Saml2AuthenticationRequestResolver
would be a convenient way to customize the AuthnRequest based on inputs from the request as well as the RelyingPartyRegistration
.
The OpenSAML implementation would have a method setAuthnRequestCustomizer
similar to OAuth2AuthenticationRequestResolver#setAuthenticationRequestCustomizer
. This method would overcome a limitation in OpenSamlAuthenticationRequestFactory
's equivalent method setAuthenticationRequestContextConverter
, which is that it does not have access to the HttpServletRequest
.
This component would supercede Saml2AuthenticationRequestContextResolver
, Saml2AuthenticationRequestContext
, and Saml2AuthenticationRequestFactory
reducing configuration like:
public class MySaml2AuthenticationRequestContext extends Saml2AuthenticationRequestContext {
boolean force;
public MySaml2AuthenticationRequestContext(Saml2AuthenticationRequestContext parent, boolean force) {
super(parent.getRelyingPartyRegistration(), parent.getIssuer(),
parent.getAssertionConsumerServiceUrl(), parent.getRelayState());
this.force = force;
}
public boolean isForce() {
return this.force;
}
}
// ...
@Component
public class AuthnRequestConverter implements
Converter<MySaml2AuthenticationRequestContext, AuthnRequest> {
private final AuthnRequestBuilder authnRequestBuilder;
private final IssuerBuilder issuerBuilder;
// ... constructor
public AuthnRequest convert(Saml2AuthenticationRequestContext context) {
MySaml2AuthenticationRequestContext myContext = (MySaml2AuthenticationRequestContext) context;
Issuer issuer = issuerBuilder.buildObject();
issuer.setValue(myContext.getIssuer());
AuthnRequest authnRequest = authnRequestBuilder.buildObject();
authnRequest.setIssuer(issuer);
authnRequest.setDestination(myContext.getDestination());
authnRequest.setAssertionConsumerServiceURL(myContext.getAssertionConsumerServiceUrl());
// ... additional settings
authRequest.setForceAuthn(myContext.getForceAuthn());
return authnRequest;
}
}
// ...
@Bean
Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver() {
Saml2AuthenticationRequestContextResolver resolver =
new DefaultSaml2AuthenticationRequestContextResolver();
return request -> {
Saml2AuthenticationRequestContext context = resolver.resolve(request);
return new MySaml2AuthenticationRequestContext(context, request.getParameter("force") != null);
};
}
@Bean
Saml2AuthenticationRequestFactory authenticationRequestFactory(
AuthnRequestConverter authnRequestConverter) {
OpenSaml4AuthenticationRequestFactory authenticationRequestFactory =
new OpenSaml4AuthenticationRequestFactory();
authenticationRequestFactory.setAuthenticationRequestContextConverter(authnRequestConverter);
return authenticationRequestFactory;
}
to
@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver(
RelyingPartyRegistrationResolver registrations) {
OpenSamlAuthenticationRequestResolver resolver = new OpenSamlAuthenticationRequestResolver(registrations);
resolver.setAuthnRequestCustomizer((tuple) -> {
HttpServletRequest request = tuple.getRequest();
AuthnRequest authnRequest = tuple.getAuthnRequest();
authnRequest.setForceAuthn(request.getParameter("force") != null);
});
}
It would also bring the SAML 2.0 support into closer alignment with the OAuth 2.0 support.
Using Saml2AuthenticationRequestContextResolver
, Saml2AuthenticationRequestContext
, and Saml2AuthenticationRequestFactory
will still continue to work and be supported, though moving to Saml2AuthenticationRequestResolver
would be encouraged.
A related discussion about motives can be found starting at #8141 (comment). This would also obviate the need for #9209 and would close #9199.