InResponseToField of the Response doesn't correspond to sent message: SAML error SpringSecurity - 4.2.13-RELEASE

2.6k views Asked by At

My web application is deployed on Amazon ECS and uses an ALB and access this application from a bastion host. I am using Okta for SSO. The login page is redirected successfully to Okta and after authentication when the request comes back to the application server, I get the following error -

Caused by: org.opensaml.common.SAMLException: InResponseToField of the Response doesn't correspond to sent message a491gda80cgh3a2b5bb3j8ebd515d2
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:139)

I am using a CustomSAMLContextProvider and setting the MessageStorageFactory to EmptyStorageFactory as suggested in other answers. I am not sure why this check is still happening.

Here is my custom SAMLContextProviderImpl class -

public class SAMLMultipleEndpointContextProvider extends SAMLContextProviderImpl {

    /**
     * Creates a SAMLContext with local entity values filled. LocalEntityId is set to server name of the request. Also
     * request and response must be stored in the context as message transports.
     *
     * @param request  request
     * @param response response
     * @return context
     * @throws MetadataProviderException in case of metadata problems
     */
    @Override
    public SAMLMessageContext getLocalEntity(HttpServletRequest request, HttpServletResponse response) throws MetadataProviderException {

        SAMLMessageContext context = new SAMLMessageContext();
        populateGenericContext(request, response, context);
        populateLocalEntityId(context, request.getServerName());
        populateLocalContext(context);
        return context;
    }

    /**
     * Creates a SAMLContext with local entity and peer values filled. LocalEntityId is set to server name of the
     * request. Also request and response must be stored in the context as message transports. Should be used when both
     * local entity and peer entity can be determined from the request.
     *
     * @param request  request
     * @param response response
     * @return context
     * @throws MetadataProviderException in case of metadata problems
     */
    @Override
    public SAMLMessageContext getLocalAndPeerEntity(HttpServletRequest request, HttpServletResponse response) throws MetadataProviderException {

        SAMLMessageContext context = new SAMLMessageContext();
        populateGenericContext(request, response, context);
        populateLocalEntityId(context, request.getServerName());
        populateLocalContext(context);
        populatePeerEntityId(context);
        populatePeerContext(context);
        return context;
    }

    /**
     * Populate LocalEntityId with retrieved entityId from metadata manager using given localAlias parameter value.
     */
    @Override
    public void populateLocalEntityId(SAMLMessageContext context, String localAlias) throws MetadataProviderException {
        String entityId = metadata.getEntityIdForAlias(localAlias);
        QName localEntityRole = SPSSODescriptor.DEFAULT_ELEMENT_NAME;

        if (entityId == null) {
            throw new MetadataProviderException("No local entity found for alias " + localAlias + ", verify your configuration.");
        } else {
            logger.debug("Using SP {} specified in request with alias {}", entityId, localAlias);
        }

        context.setLocalEntityId(entityId);
        context.setLocalEntityRole(localEntityRole);
    }

    /**
     * Disable the check for InResponseToField from SSO message response.
     */
    @Override
    public void setStorageFactory(SAMLMessageStorageFactory storageFactory) {
        super.setStorageFactory(new EmptyStorageFactory());
    }
}
1

There are 1 answers

0
Bernhard Thalmayr On BEST ANSWER

In order to comply with the rules defined in the SAML spec, the SAML response has to be validated against the SAML AuthNRequest in SP-initiated SSO flow. By default Spring SAML stores the SAML AuthNRequest in memory, hence the HTTP POST request containing the SAML response as payload MUST hit the same JVM where the AuthNRequest was created. If the LB can not guarantee stickiness, then you need to implement a message store ( org.springframework.security.saml.storage.SAMLMessageStorage , org.springframework.security.saml.storage.SAMLMessageStorageFactory) that can share the messages with multiple instances. Make sure that you delete the message from the store after consumption to circumvent replay attacks as SAML resonses are meant for one-time-usage.