The authentication manager of the Saml2WebSsoAuthenticationFilter can be overwritten, using a custom AuthenticationManager implementation. This authentication manager should expect a Saml2AuthenticationToken object containing the SAML 2 Response XML data. However in our use case it would be preferred to extend the default OpenSamlAuthenticationProvider in order to use the OpenSamlImplementation functionality to parse the Saml2Response XML. However currently the methods OpenSamlAuthenticationProvider#parse and OpenSamlAuthenticationProvider#validateResponse are private.
Another way to increase the extensibility is to make the OpenSamlImplementation class public as access is now package only.
Yet another approach is to introduce an userAttributesExtractor similar as the current authoritiesExtractor but then for user attributes. This would allow extracting user attributes from the Assertion. This new userAttributesExtractor can be injected in the OpenSamlAuthenticationProvider using the already documented ObjectPostProcessor<OpenSamlAuthenticationProvider>. If not null the results of the userAttributesExtractor (something like Map<String, List<? extends Serializable>> userAttributes)
can be stored in the Saml2Authentication to be available wherever an Authentication is used to identify the logged in user.
I would be happy to write a PR, but would need some input as to which direction is preferred. I would prefer the last approach.
Comment From: oharsta
In release 5.4.x there is a hook to accomplish this:
@Override
protected void configure(HttpSecurity http) throws Exception {
OpenSamlAuthenticationProvider authenticationProvider = new OpenSamlAuthenticationProvider();
authenticationProvider.setResponseAuthenticationConverter(r -> {
//Use the OpenSamlAuthenticationProvider.ResponseToken to construct an AbstractAuthenticationToken subclass
return new TestingAuthenticationToken(r.getResponse().getAssertions().get(0).getSubject().getNameID().getValue(), "n/a");
});
This meets our requirements. Closing this issue.
Comment From: jzheaux
@oharsta, glad to hear the new setter works for you! Thanks for your response.
Comment From: oharsta
@jzheaux, in order to unit test our ResponseAuthenticationConverter I was forced to use trickery reflection to construct the org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider$ResponseToken. You might want to make the constructor of this inner static class public
Comment From: jzheaux
@oharsta, can you clarify what is package-private that you need to be public? ResponseToken is already public.
Comment From: oharsta
@jzheaux The constructor of OpenSamlAuthenticationProvider.ResponseToken is not public.
Comment From: jzheaux
Can you explain why you need to construct one? The converter is given a ResponseToken, it does not return one. Maybe a code sample would clarify what I'm not seeing.
Comment From: oharsta
It is for unit testing any custom implementation of the ResponseAuthenticationConverter. In the unit test you'll want to call the method:
public AbstractAuthenticationToken convert(OpenSamlAuthenticationProvider.ResponseToken source)
And to do so, you'll need to create a OpenSamlAuthenticationProvider.ResponseToken which is not possible. See https://github.com/OpenConext/OpenConext-oidcng/blob/master/src/test/java/oidc/saml/ResponseAuthenticationConverterTest.java#L88 to clarify what I mean.
Comment From: jzheaux
Ah, gotcha, @oharsta. Thank you for the clarification.
Would you be able to provide a PR with the needed changes?