Spring 会话升级后 InResponseToField 错误

InResponseToField error after Spring Session upgrade

由于以下原因,我们无法从 Spring 会话 1.3.3 升级到 2.1.2 Spring 安全 SAML 的问题。似乎 Spring 安全 SAML 无法验证 InResponseToField 值,因为两个会话 ID 是 正在创建:

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

我扩展了 SAMLContextProvider 的 HttpSessionStorageFactory 使用并添加了一些日志记录以了解发生了什么:

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

[用户现在被重定向到 IdP,稍后被送回 申请]

现在出现以下错误:

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

这也是我们记录的内容:

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

请注意会话 ID 已更改,这就是为什么 SAMLException 被抛出——它找不到值,因为它已被存储 在另一个会话中。

另一件事。只有一个 IdP 失败,它使用 HTTP Post 进行 SSO 响应绑定。另一个有效,是使用 Artifact over HTTP Redirect。

Spring 使用@EnableRedisHttpSession 注解配置会话。

如果我调试Redis中的内容,我能看到的就是这个

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"
[…]

我也试过两件事都没有成功:

  1. 将 redisFlushMode 设置为立即:

    @EnableRedisHttpSession(redisNamespace = "nettskjema", maxInactiveIntervalInSeconds = 10800, redisFlushMode = RedisFlushMode.IMMEDIATE)
    
  2. 已配置 Spring 始终创建会话的安全性:

    create-session="always"
    

这是我们正在使用的库和 Redis 版本。请注意,我们使用的是 Jedis 而不是 Lettuce:

我找到了问题的根源。它与 Spring 会话 2.* 中添加的 SameSite cookie 属性有关。由于我们的 IdP (SAML) 与我们的应用程序相比有其他域,因此默认的 lax 值导致了一些问题。诀窍是将 DefaultCookieSerializer 中的 sameSite 属性设置为 null,如下所示:

serializer.setSameSite(null);

万一有人还在用XML

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

Spring 安全文档是这样描述这个错误的:

确保应用程序在发送请求和接收响应期间使用相同的 HttpSession。

在我们的例子中,我们导航到 DNS 主机名以启动身份验证,但 SAML 配置为重定向到机器名称。由于 SameSite 是在与授权请求关联的 JSESSIONID 上强制执行的,因此浏览器未将会话 cookie 包含在授权响应中,并引发了此错误(尽管响应中的 InResponseTo 值与身份验证请求的 ID 匹配...所以我猜你不能从字面上理解错误。)

现在浏览器已将默认的 SameSite 行为从 none 更改为 Lax(未指定时),这似乎更常发生。 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite

tl;dr - 确保您通过身份验证流程以完全相同的域名开始和结束。