With the deprecated Saml2AuthenticationRequestContext it was possible to set a custom RelayState, but with the new OpenSamlAuthenticationRequestResolver it is always initialized to:

String relayState = UUID.randomUUID().toString();

I don't see a way to overcome this without implementing my own AuthenticationRequestResolver, is there a reason for this?

Comment From: jzheaux

Hi, @exeba. The purpose of deprecating the other classes was to simplify the API to a single interface. So, to have a custom relay state, you create a custom resolver that delegates like so:

@Bean 
Saml2AuthenticationRequestResolver authenticationRequestResolver(
        RelyingPartyRegistrationResolver registrations) {
    OpenSaml4AuthenticationRequestResolver authenticationRequests = 
            new OpenSaml4AuthenticationRequestResolver(registrations);
    return (request) -> {
        Saml2PostAuthenticationRequest post = authenticationRequests.resolve(request);
        RelyingPartyRegistration registration = registrations.resolve(request, "registration-id");
        String relayState = resolveCustomRelayState(request);
        return Saml2PostAuthenticationRequest.withRelyingPartyRegistration(registration)
                .samlRequest(post.getSamlRequest())
                .authenticationRequestUri(post.getAuthenticationRequestUri())
                .relayState(relayState)
                .build();
    }
}

That said, I think this can be simplified. For example, it would be nicer to not have to waste the CPU on generating a relay state if the app is going to override it. To that end, I think we should add a setRelayStateResolver(Converter<HttpServletRequest, String> relayStateResolver) method. The default value would be one that randomly generates the relay state.

The resulting configuration would then instead be:

@Bean 
Saml2AuthenticationRequestResolver authenticationRequestResolver(
        RelyingPartyRegistrationResolver registrations) {
    OpenSaml4AuthenticationRequestResolver authenticationRequests = 
            new OpenSaml4AuthenticationRequestResolver(registrations);
    authenticationRequests.setRelayStateResolver(this::resolveCustomRelayState);
    return authenticationRequests;
}

Would this address your concern and, if so, are you able to submit a PR that adds the setter?

Comment From: Martin-Office

Hi @jzheaux, Your bean proposition to set custom relayState look interesting but sadly there is no bean RelyingPartyRegistrationResolver registrations for autowiring. How can I use the instance created by the framework? In my configuration I only do this: http.saml2Login(saml -> saml.successHandler(new Saml2AuthenticationSuccessHandler())) I though of creating a bean with DefaultRelyingPartyRegistrationResolver but this one needs RelyingPartyRegistrationRepository which needs RelyingPartyRegistration(s). I feel like I need to rebuild everything to only set a simple resolver... Maybe I do not understand how the framework is wired or how to use existing setup with my beans.

In fact how can I create a bean that uses instances that are created after the HttpSecurity build the SecurityFilterChain.

Comment From: Martin-Office

Ok I can use autowiring of Saml2RelyingPartyProperties to avoid hardcoding the configuration... @Bean public RelyingPartyRegistrationRepository relyingPartyRegistrations( Saml2RelyingPartyProperties relyingPartyProperties) { then it become managable....