替换AuthorizationRequest后,HttpSession为null

Cod*_*Med 23 spring spring-mvc spring-security spring-boot spring-oauth2

下面给出了快速重现问题的完整代码和说明.


问题:
HttpSession成为null以后的自定义实现DefaultOAuth2RequestFactory替换当前AuthorizationRequest与保存AuthorizationRequest. 这将导致后续请求失败/oauth/token,因为CsrfFilter在之前的春季安全过滤器链/oauth/token端点无法找到一个session Csrf tokennull session与比较requestCsrf token.


在错误期间控制流量:

以下流程图说明了步骤14步骤15以某种方式 - null通知HttpSession.(或者可能不匹配a JSESSIONID.)在步骤14SYSO开始时的A 表明确实存在确实包含正确的.然而,不知何故,当步骤15触发从URL 处的客户端返回到端点的呼叫时,已经变为. CustomOAuth2RequestFactory.javaHttpSessionCsrfTokenHttpSessionnulllocalhost:8080/loginlocalhost:9999/oauth/token

断点被添加到HttpSessionSecurityContextRepository下面的调试日志中提到的每一行.(它位于在Maven Dependencies所述的夹authservereclipse项目.)这些断点确认HttpSessionnull,当向最终请求/oauth/token在下面的流程图制备.(左下角流程图)null HttpSession可能是由于JSESSIONID定制后残留在浏览器成为过时的DefaultOAuth2RequestFactory代码运行.

如何修复此问题,以便在流程图中步骤15结束后,在HttpSession最终调用/oauth/token端点期间保留相同的问题?


相关代码和日志:

CustomOAuth2RequestFactory.java 单击此链接可在文件共享站点查看 完整代码.我们可以猜测,这null session是由于1.)JSESSIONID没有在浏览器中通过代码中的更新CustomOAuth2RequestFactory,或2.)HttpSession实际被null认证.

步骤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
Run Code Online (Sandbox Code Playgroud)


在您的计算机上重新创建问题:

您可以通过以下简单步骤在几分钟内在任何计算机上重新创建问题:

1.)通过单击此链接从文件共享站点下载应用程序压缩版本.

2.)键入以下内容解压缩应用程序: tar -zxvf oauth2.tar(4).gz

3.)authserver通过导航到oauth2/authserver然后键入来启动应用程序mvn spring-boot:run.

4.)resource通过导航到oauth2/resource然后键入来启动应用程序mvn spring-boot:run

5.)ui通过导航到oauth2/ui然后键入来启动应用程序mvn spring-boot:run

6.)打开Web浏览器并导航到 http : // localhost : 8080

7.)单击Login,然后Frodo以用户MyRing身份和密码输入,然后单击以提交.

8)输入5309Pin Code,然后点击提交. 这将触发上面显示的错误.

春引导调试日志将显示的很多SYSO,这给变量的值,例如XSRF-TOKENHttpSession在流程图中所示的每个步骤.该SYSO让他们更容易理解有助于段的调试日志.所有这些SYSO都是由其他类调用的一个类完成的,因此您可以操纵SYSO-generating类来更改控制流中的报表.SYSO生成类的名称是TestHTTP,它的源代码可以在同一个demo包中找到.


使用调试员:

1.)选择运行authserver应用程序的终端窗口,然后键入Ctrl-C以停止authserver应用程序.

2.)将三个应用程序(authserver,resourceui)作为现有的maven项目导入eclipse .

3.)在authserver应用程序的eclipse Project Explorer中,单击以展开Maven Dependencies文件夹,然后在其中向下滚动以单击以展开Spring-Security-web...jar,如下图中橙色圆圈所示.然后滚动查找并展开org.springframework.security.web.context包.然后双击打开HttpSessionSecurityContextRepository下面屏幕截图中以蓝色突出显示的类.将断点添加到此类中的每一行.您可能希望对SecurityContextPersistenceFilter同一包中的类执行相同操作. 这些断点将使您能够查看HttpSession当前null在控制流结束之前的值,但需要具有可映射到a的有效值XSRF-TOKEN以便解析此OP.

4.)在应用程序demo包中,在内部添加断点CustomOAuth2RequestFactory.java.然后Debug As... Spring Boot App启动调试器.

5.)然后重复上面的步骤6到8.您可能希望在每次新尝试之前清除浏览器的缓存.您可能希望打开浏览器开发人员工具的"网络"选项卡.

Ala*_*how 1

你的问题解决了吗?我一直在寻找 2FA 和 spring-security-oauth2 的完整示例。很高兴您发布了完整的概念和完整的来源。

我尝试了您的软件包,只需更改 AuthserverApplication.java 中的 1 行代码即可解决您的问题

@Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .formLogin().loginPage("/login").permitAll()
        .and()
                .requestMatchers().antMatchers("/login", "/oauth/authorize", "/secure/two_factor_authentication", "/pincode")
        .and()
                .authorizeRequests().anyRequest().authenticated();
        // @formatter:on
    }
Run Code Online (Sandbox Code Playgroud)

您的原始配置通过了 Spring Security 的身份验证链,它返回了一个空的身份验证对象。

我还建议您将 CustomOAuth2RequestFactory 的 Bean 创建更改为以下内容,以覆盖链中的所有 OAuth2RequestFactory

@Bean
    public OAuth2RequestFactory customOAuth2RequestFactory(){
        return new CustomOAuth2RequestFactory(clientDetailsService);
    }
Run Code Online (Sandbox Code Playgroud)

对于您添加的用于处理 CSRF 的代码,您可以简单地删除它们,例如:2FA 控制器:

@Controller
@RequestMapping(TwoFactorAuthenticationController.PATH)
public class TwoFactorAuthenticationController {
    private static final Logger LOG = LoggerFactory.getLogger(TwoFactorAuthenticationController.class);
    public static final String PATH = "/secure/two_factor_authentication";
    public static final String AUTHORIZE_PATH = "/oauth/authorize";
    public static final String ROLE_TWO_FACTOR_AUTHENTICATED = "ROLE_TWO_FACTOR_AUTHENTICATED";

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @RequestMapping(method = RequestMethod.GET)
    public String auth(HttpServletRequest request, HttpSession session, HttpServletResponse resp/*, ....*/) {
        System.out.println("-------- inside GET /secure/two_factor_authentication --------------");
        if (AuthenticationUtil.isAuthenticatedWithAuthority(ROLE_TWO_FACTOR_AUTHENTICATED)) {
            LOG.info("User {} already has {} authority - no need to enter code again", ROLE_TWO_FACTOR_AUTHENTICATED);
//            throw ....;
        }
        else if (session.getAttribute(CustomOAuth2RequestFactory.SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME) == null) {
//            LOG.warn("Error while entering 2FA code - attribute {} not found in session.", CustomOAuth2RequestFactory.SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME);
//          throw ....;
        }
        return "pinCode";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String auth(FormData formData, HttpServletRequest req, HttpServletResponse resp,
                                            SessionStatus sessionStatus, Principal principal, Model model)
        throws IOException{

        if (formData.getPinVal()!=null) {
            if(formData.getPinVal().equals("5309")){
                AuthenticationUtil.addAuthority(ROLE_TWO_FACTOR_AUTHENTICATED);
                return "redirect:"+AUTHORIZE_PATH;
            };
        };

        return "pinCode";
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想要清理后的完整源代码,请告诉我。