【发布时间】:2016-09-28 19:51:36
【问题描述】:
Complete code 和快速重现问题的说明如下。
问题:
在
DefaultOAuth2RequestFactory 的自定义实现将当前AuthorizationRequest 替换为保存的AuthorizationRequest 后,HttpSession 变为null。这会导致后续请求失败到 /oauth/token 因为 /oauth/token 端点之前的 Spring Security 过滤器链中的 CsrfFilter 无法在 null 中找到 session Csrf token session 与 request 的比较Csrf token。
错误期间的控制流程:
以下流程图说明了 Step 14 和 Step 15 以某种方式 null-ify HttpSession。 (或者可能与JSESSIONID 不匹配。)在第14 步 中CustomOAuth2RequestFactory.java 开头的SYSO 表明确实有一个HttpSession 实际上包含正确的CsrfToken .然而,不知何故,当 Step 15 触发来自客户端的调用时,HttpSession 已变为 nulllocalhost:8080/login url 返回localhost:9999/oauth/token 端点。
在下面的调试日志中提到的HttpSessionSecurityContextRepository 的每一行都添加了断点。 (它位于authserver eclipse 项目的Maven Dependencies 文件夹中。)当在下面的流程图中发出对/oauth/token 的最终请求时,这些断点确认HttpSession 是null。 (流程图的左下角。) null HttpSession 可能是由于自定义 DefaultOAuth2RequestFactory 代码运行后保留在浏览器中的 JSESSIONID 已过期。
如何解决此问题,以便在流程图中第 15 步结束后,在对/oauth/token 端点的最终调用期间保持相同的HttpSession?
相关代码和日志:
CustomOAuth2RequestFactory.javacan be viewed at a file sharing site by clicking on this link.的完整代码我们可以猜测nullsession是由于1.)JSESSIONID没有在浏览器中被@中的代码更新987654370@,或 2.) HttpSession 实际上是 null-ified。
在Step 15之后调用/oauth/token的Spring Boot调试日志清楚地表明此时没有HttpSession,可以这样解读:
2016-05-30 15:33:42.630 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /oauth/token at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /oauth/token at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /oauth/token at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@2fe29f4b
2016-05-30 15:33:42.631 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.FilterChainProxy : /oauth/token at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
2016-05-30 15:33:42.644 DEBUG 13897 --- [io-9999-exec-10] o.s.security.web.csrf.CsrfFilter : Invalid CSRF token found for http://localhost:9999/uaa/oauth/token
2016-05-30 15:33:42.644 DEBUG 13897 --- [io-9999-exec-10] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2016-05-30 15:33:42.644 DEBUG 13897 --- [io-9999-exec-10] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
在您的计算机上重现问题:
按照这些简单的步骤,您只需几分钟即可在任何计算机上重现问题:
1.) 下载zipped version of the app from a file sharing site by clicking on this link。
2.) 输入解压应用程序:tar -zxvf oauth2.tar(4).gz
3.) 导航至oauth2/authserver,然后输入mvn spring-boot:run,启动authserver 应用程序。
4.) 导航至oauth2/resource,然后输入mvn spring-boot:run,启动resource 应用程序
5.) 导航至oauth2/ui,然后输入mvn spring-boot:run 启动ui 应用程序
6.) 打开网络浏览器并导航到http : // localhost : 8080
7.) 点击Login,然后输入Frodo作为用户,MyRing作为密码,然后点击提交。
8.) 输入5309 作为Pin Code,然后单击提交。 这将触发上面显示的错误。
Spring Boot 调试日志将显示 A LOT of SYSO,其中在流程图所示的每个步骤中给出了变量的值,例如 XSRF-TOKEN 和 HttpSession。 SYSO 有助于对调试日志进行分段,以便更容易解释。并且所有SYSO 都是由其他类调用的一个类完成的,因此您可以操纵SYSO-generating 类来更改控制流中各处的报告。 SYSO-generating 类的名称是TestHTTP,它的源代码可以在同一个demo 包中找到。
使用调试器:
1.) 选择正在运行authserver 应用程序的终端窗口并键入Ctrl-C 以停止authserver 应用程序。
2.) 将三个应用程序(authserver、resource 和 ui)作为现有的 maven 项目导入 eclipse。
3.) 在 authserver 应用程序的 eclipse 项目资源管理器中,单击展开 Maven Dependencies 文件夹,然后在其中向下滚动以单击展开 Spring-Security-web... jar 如下图橙色圆圈所示。然后滚动查找并展开org.springframework.security.web.context 包。然后双击打开下面屏幕截图中以蓝色突出显示的HttpSessionSecurityContextRepository 类。向此类中的每一行添加断点。您可能希望对同一包中的 SecurityContextPersistenceFilter 类执行相同的操作。 这些断点可以让你看到HttpSession的值,目前在控制流结束前变成null,但需要有一个可以映射到@的有效值987654415@ 以解决此 OP。
4.) 在应用程序的 demo 包中,在 CustomOAuth2RequestFactory.java 内添加断点。然后Debug As... Spring Boot App 启动调试器。
5.) 然后重复上面的步骤 6 到 8。您可能希望在每次新尝试之前清除浏览器的缓存。您可能希望打开浏览器开发工具的“网络”选项卡。
【问题讨论】:
标签: spring spring-mvc spring-security spring-boot spring-oauth2