'InResponseToField error after Spring Session upgrade

We are not able to upgrade from Spring session 1.3.3 to 2.1.2 due to problems with Spring Security SAML. It seems that Spring Security SAML cannot verify the InResponseToField value because two session IDs are being created:

Caused by: org.opensaml.common.SAMLException: InResponseToField of the Response doesn't correspond to sent message abc7b9acgecbde41927g729143f1g2

I have extended the HttpSessionStorageFactory which SAMLContextProvider uses and added some logging in order to find out what's going on:

INFO 18.12.2018 13:43:27:95 (SAMLDelegatingAuthenticationEntryPoint.java:commence:105) - Session ID before redirect: 205e92ea-7ff3-45be-bfd1-648c2ae8da8e
INFO 18.12.2018 13:43:27:111 (SamlAuthenticationConfig.java:storeMessage:413) - Storing message abc7b9acgecbde41927g729143f1g2 to session 205e92ea-7ff3-45be-bfd1-648c2ae8da8e

[The user is now beeing redirected to the IdP and later sent back to the application]

Now the following error occurs:

Caused by: org.opensaml.common.SAMLException: InResponseToField of the Response doesn't correspond to sent message abc7b9acgecbde41927g729143f1g2

And this is what we also have logged:

INFO 18.12.2018 13:43:27:466 (SamlAuthenticationConfig.java:retrieveMessage:429) - Message abc7b9acgecbde41927g729143f1g2 not found in session 1bc1f535-9207-4a81-b1ee-031fecc12a79

Notice that the session ID has changed which is the reason why the SAMLException is thrown—it cannot find the value because it's stored in another session.

Another thing. Only one IdP fails which is using HTTP Post for SSO response binding. The other one, which works, is using Artifact over HTTP Redirect.

Spring Session is configured using the @EnableRedisHttpSession annotation.

If I debug the contents in Redis, this is what I can see.

w3test-jb03.uio.no:6379> KEYS *nettskjema*
1) "nettskjema:expirations:1545140940000"
[…]
22) "nettskjema:expirations:1545144240000"
23) "nettskjema:sessions:expires:8ae32bf8-28a2-422f-a96a-e42e0a52457a"
24) "nettskjema:expirations:1545137580000"
[…]
36) "nettskjema:expirations:1545146040000"
37) "nettskjema:sessions:8ae32bf8-28a2-422f-a96a-e42e0a52457a"
38) "nettskjema:expirations:1545147000000"
[…]
43) "nettskjema:expirations:1545147120000"
44) "nettskjema:sessions:expires:205e92ea-7ff3-45be-bfd1-648c2ae8da8e"
45) "nettskjema:expirations:1545141900000"
[…]
48) "nettskjema:expirations:1545146400000"
49) "nettskjema:sessions:20afd141-e797-46a3-a6cf-efe8559280cb"
50) "nettskjema:expirations:1545142080000"
[…]
54) "nettskjema:expirations:1545142200000"
55) "nettskjema:sessions:84ff3f22-edf6-400b-83fd-b2e7627acfd3"
56) "nettskjema:expirations:1545145440000"
[…]
62) "nettskjema:expirations:1545145320000"
63) "nettskjema:sessions:expires:517dd25a-f743-47d5-8ad6-96fc3aa34eb2"
64) "nettskjema:expirations:1545138720000"
[…]
95) "nettskjema:expirations:1545137040000"
96) "nettskjema:sessions:517dd25a-f743-47d5-8ad6-96fc3aa34eb2"
97) "nettskjema:expirations:1545144120000"
[…]
100) "nettskjema:expirations:1545140760000"
101) "nettskjema:sessions:5c937506-2ea2-4dc1-94e8-d048d7591a87"
102) "nettskjema:expirations:1545138960000"
[…]
104) "nettskjema:expirations:1545141300000"
105) "nettskjema:sessions:expires:1bc1f535-9207-4a81-b1ee-031fecc12a79"
106) "nettskjema:expirations:1545143280000"
[…]
122) "nettskjema:expirations:1545139440000"
123) "nettskjema:sessions:expires:20bda413-93c6-4475-9163-a88a5689e4ed"
124) "nettskjema:expirations:1545143760000"
[…]
135) "nettskjema:expirations:1545147480000"
136) "nettskjema:sessions:expires:a546038a-bac7-42c1-bb53-2c1b9973fa97"
137) "nettskjema:expirations:1545145620000"
[…]
143) "nettskjema:expirations:1545146880000"
144) "nettskjema:sessions:expires:20afd141-e797-46a3-a6cf-efe8559280cb"
145) "nettskjema:sessions:8cf6b02c-3ac2-4974-a516-83ffd6fbb98c"
146) "nettskjema:expirations:1545144300000"
[…]
149) "nettskjema:expirations:1545141720000"
150) "nettskjema:sessions:expires:8cf6b02c-3ac2-4974-a516-83ffd6fbb98c"
151) "nettskjema:expirations:1545137220000"
[…]
157) "nettskjema:expirations:1545138180000"
158) "nettskjema:sessions:20bda413-93c6-4475-9163-a88a5689e4ed"
159) "nettskjema:expirations:1545146220000"
160) "nettskjema:expirations:1545142380000"
161) "nettskjema:sessions:b32daccd-7e81-4faa-9ae6-11803392f4f1"
162) "nettskjema:expirations:1545137340000"
163) "nettskjema:expirations:1545138420000"
164) "nettskjema:sessions:a546038a-bac7-42c1-bb53-2c1b9973fa97"
165) "nettskjema:sessions:7cf0b74b-5266-42ed-a966-34e34f423396"
166) "nettskjema:expirations:1545146160000"
[…]
169) "nettskjema:expirations:1545139980000"
170) "nettskjema:sessions:1bed0254-b8f5-4fc4-8da2-5805eb130a82"
171) "nettskjema:expirations:1545143400000"
[…]
192) "nettskjema:expirations:1545146580000"
193) "nettskjema:sessions:expires:5c937506-2ea2-4dc1-94e8-d048d7591a87"
194) "nettskjema:expirations:1545139320000"
195) "nettskjema:sessions:c7fb8653-6985-47c2-9bd6-f3012665ca83"
196) "nettskjema:expirations:1545138660000"
197) "nettskjema:sessions:205e92ea-7ff3-45be-bfd1-648c2ae8da8e"
198) "nettskjema:expirations:1545139140000"
[…]
201) "nettskjema:expirations:1545143820000"
202) "nettskjema:sessions:1bc1f535-9207-4a81-b1ee-031fecc12a79"
203) "nettskjema:expirations:1545142980000"
[…]

I have tried two things as well with no luck:

  1. Set redisFlushMode to IMMEDIATE:

    @EnableRedisHttpSession(redisNamespace = "nettskjema", maxInactiveIntervalInSeconds = 10800, redisFlushMode = RedisFlushMode.IMMEDIATE)
    
  2. Configured Spring Security to always create sessions:

    create-session="always"
    

This is the library and Redis versions we are using. Note that we are using Jedis and not Lettuce:

  • Redis server v=3.2.10 (Redis Sentinel)
  • spring.session.data.redis.version: 2.1.2.RELEASE
  • spring.security.version: 5.1.1.RELEASE
  • org.springframework.version: 5.1.3.RELEASE
  • jedis.version: 2.9.0


Solution 1:[1]

I found the source of the problem. It was related to the SameSite cookie attribute which was added in Spring Session 2.*. Since our IdP (SAML) had an other domain compared to our application, the default lax value caused some problems. The trick was to set the sameSite attribute in DefaultCookieSerializer to null like this:

serializer.setSameSite(null);

Solution 2:[2]

In case anyone still uses XML

<bean id="serializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
    <property name="sameSite"><null /></property>
</bean>

Solution 3:[3]

The Spring Security doc says this about this error:

Make sure that application uses the same HttpSession during sending of the request and reception of the response.

In our case, we were navigating to a DNS hostname to initiate authentication, but SAML was configured to redirect to the machine name. Since SameSite is being enforced on the JSESSIONID associated with the authorization request, the browser did not include the session cookie with the authorization response, and this error was thrown (despite the fact that the InResponseTo value in the response matched the ID of the auth request ... so I guess you can't take the error literally.)

It seems this might happen more often now that browsers have changed the default SameSite behavior from none to Lax (when not specified). https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite

tl;dr - make sure you start and end at the exact same domain name via your authentication flow.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Erlend GarĂ¥sen
Solution 2 brightmatter
Solution 3 em_bo