Summary

Current codes doesn't seem to provide the way to get RelayState from authenticationManager, Saml2AuthenticationTokenConverter in order to work with custom logic.

Actual Behavior

There seems to have no methods to provide RelayState from SAMLResponse step. So need to create Saml2AuthenticationToken, Saml2AuthenticationTokenConverter. Ended up, I got blocked by OpenSaml4AuthenticationProvider

Expected Behavior

I want to have RelayState value in the scope of setResponseAuthenticationConverter or authenticationConverter

Configuration

spring security saml provider, spring

Version

spring security saml provider - 5.5.3

Sample

AuthenticationProvider.setResponseAuthenticationConverter((Converter)new CustomResponseSaml2AuthenticationTokenConverter(
                        relyingPartyRegistrationResolver));
                (responseToken) -> {
// responseToken.getRelayState() like this? or other steps in processing SAMLResponse
});

Comment From: marcusdacoregio

Hi @fr2lancer. Thanks for reaching out.

The responseAuthenticationConverter is a converter the receives the ResponseToken (Converter<ResponseToken, ? extends AbstractAuthenticationToken>). The RelayState is present inside the ResponseToken via ResponseToken.token.authenticationRequest.relayState, so if you define a custom response authentication converter you can get it.

Does it solve your problem or I didn't understand your question?

Comment From: fr2lancer

Hi @marcusdacoregio

Thanks for the response for my question.

Just In 5.5.3,

ResponseToken.token -> Saml2AuthenticationToken

It doesn't seem to have authenticationRequest as either in members and methods

any specific version required in spring, spring-security ?

Thank you.

Comment From: marcusdacoregio

Hi @fr2lancer.

I'm sorry, I forgot to mention that the authenticationRequest field is introduced in 5.6 by https://github.com/spring-projects/spring-security/issues/9185. The 5.6.0 version will be released on November 15th, in the meantime, you could use the Spring Security 5.6.0-RC3 version.

Are you able to upgrade the version?

Comment From: fr2lancer

Hi. Today now I can test this with 5.6.0-RC1 ( 5.6.0-RC3 hasn't been released yet..?)

when I tested "ResponseToken.token.authenticationRequest " with http request, it actually get null before the getting RelayStatus() The reason seems to be below :

  1. HttpSessionSaml2AuthenticationRequestRepository::loadAuthenticationRequest is loaded by :
AbstractSaml2AuthenticationRequest authenticationRequest = loadAuthenticationRequest(request);
        return new Saml2AuthenticationToken(relyingPartyRegistration, saml2Response, authenticationRequest);
  1. And its logic like this :
    private static final String DEFAULT_SAML2_AUTHN_REQUEST_ATTR_NAME = HttpSessionSaml2AuthenticationRequestRepository.class
            .getName().concat(".SAML2_AUTHN_REQUEST");
...

@Override
    public AbstractSaml2AuthenticationRequest loadAuthenticationRequest(HttpServletRequest request) {
        HttpSession httpSession = request.getSession(false);
        if (httpSession == null) {
            return null;
        }
        return (AbstractSaml2AuthenticationRequest) httpSession.getAttribute(this.saml2AuthnRequestAttributeName);
    }

  1. so it won't take the value from my http request by the logic above.

  2. And I also found this code :

public void setAuthenticationRequestRepository(
            Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> authenticationRequestRepository) {
        Assert.notNull(authenticationRequestRepository, "authenticationRequestRepository cannot be null");
        this.loader = authenticationRequestRepository::loadAuthenticationRequest;
    }

    private AbstractSaml2AuthenticationRequest loadAuthenticationRequest(HttpServletRequest request) {
        return this.loader.apply(request);
    }

       -> session is null or can't find key 'DEFAULT_SAML2_AUTHN_REQUEST_ATTR_NAME '

4-1. So, is that designed to use custom Saml2AuthenticationRequestRepository in order to read values from the http request?

Env : Currently I am using MockMvcWebTestClient for integration test(it might affect this?)

Added :

After the initial comment, I found out those :

@Override
    public void saveAuthenticationRequest(AbstractSaml2AuthenticationRequest authenticationRequest,
            HttpServletRequest request, HttpServletResponse response) {
        if (authenticationRequest == null) {
            removeAuthenticationRequest(request, response);
            return;
        }
        HttpSession httpSession = request.getSession();
        httpSession.setAttribute(this.saml2AuthnRequestAttributeName, authenticationRequest);
    }

-> so it seems to be storing values from the http request to session.

And it is called only 2 places in 'Saml2WebSsoAuthenticationRequestFilter

private void sendRedirect(HttpServletRequest request, HttpServletResponse response,
            Saml2AuthenticationRequestContext context) throws IOException {
        Saml2RedirectAuthenticationRequest authenticationRequest = this.authenticationRequestFactory
                .createRedirectAuthenticationRequest(context);
        this.authenticationRequestRepository.saveAuthenticationRequest(authenticationRequest, request, response);

...

    private void sendPost(HttpServletRequest request, HttpServletResponse response,
            Saml2AuthenticationRequestContext context) throws IOException {
        Saml2PostAuthenticationRequest authenticationRequest = this.authenticationRequestFactory
                .createPostAuthenticationRequest(context);
        this.authenticationRequestRepository.saveAuthenticationRequest(authenticationRequest, request, response);

So those aren't designed to use when receive SAMLResponse ? Or it is designed to be used in sequence of exchange of SAML Request & Response? Currently MockMvcWebTestClient doesn't seem to provide the sequence of exchange..

Thank you.

Comment From: fr2lancer

Somehow I am able to get RelayState from session by using ' .apply(sharedHttpSession())' on the setup of MockMvcWebTestClient. Instead need to send a pre-request of SAMLRequest in order to store RelayState beforehand.

Thanks you all.

Comment From: meghariani

Hello @fr2lancer,

I am trying to retrieve the relaystate value from the session and I'm getting null when using getAttribute(). Can you please elaborate on how you fixed your issue? A code snippet will be very appreciated.

Thanks,