Spring Security和Google OpenID Connect迁移

ste*_*eve 14 spring-security google-openid google-oauth openid-connect

问题:

1)将OpenID Connect身份验证集成到使用Spring Security进行身份验证的Web应用程序中的最佳方法是什么?

2)有没有办法 - 从MITREid方面或Google账户方面 - 让MITREid OpenID Connect身份验证过滤器与Google的OpenID Connect服务一起使用?

我确信这些问题的答案对于使用Spring Security OpenID模块向Google进行身份验证的任何开发人员都很有用.

详情:

我的webapp使用Spring Security的OpenID模块(<openid-login .../>)进行身份验证,将Google帐户作为身份提供商.即,用户使用他们的Google Apps或GMail电子邮件地址进行身份验证.

最近,每当用户进行身份验证时,他们都会从Google帐户收到此警告消息:

重要提示:Google帐户的OpenID2将于2015年4月20日消失.

因此,谷歌正在放弃对OpenID的支持,将于2015年4月完全关闭,并声明如果您想通过Google帐户进行身份验证,则必须切换到OpenID Connect协议.

我希望Spring Security能够内置对OpenID Connect的支持,就像它内置了对OpenID的支持一样.例如像<openid-connect-login .../>元素一样的东西.但我的搜索结果却没有得到这样的支持.

我到目前为止找到的最佳候选人是MITREid Connect.它包括一个以OIDCAuthenticationFilterOpenID Connect 命名的Spring Security身份验证过滤器.问题是,它无法与Google的OpenID Connect实施互操作.

我尝试克隆MITREid simple-web-app并将其配置为使用Google帐户进行身份验证(使用OpenID Connect).但它没有用,因为它取决于Google的OpenID Connect实现不支持的随机数.来自Google帐户的错误消息是:

此消息类型不允许使用参数:nonce

接下来,我尝试将自己的MITREid AuthRequestUrlBuilder接口实现插入到MITREid配置中.我的实现和MITREid的实现之间的唯一区别是,我并没有发送随机数.

不发送nonce使得Google的OpenID Connect实现感到满意,但MITREid在Google身份验证响应中找不到nonce时抛出异常.错误消息是:

身份验证失败:ID令牌不包含nonce声明

我在MITREID'中跟踪了MITREid异常到这些行OIDCAuthenticationFilter:

// compare the nonce to our stored claim
String nonce = idClaims.getStringClaim("nonce");
if (Strings.isNullOrEmpty(nonce)) {

    logger.error("ID token did not contain a nonce claim.");

    throw new AuthenticationServiceException("ID token did not contain a nonce claim.");
}
Run Code Online (Sandbox Code Playgroud)

但是我没有办法扩展MITREid的实现以忽略nonce.如此接近,但到目前为止!如果Google帐户接受nonce或MITREid可以配置为忽略nonce,那么我们就有了解决方案.

在github上的MITREid Connect问题列表中,我发现其他人遇到了类似的问题:

1)#726 - 使用客户端与Google作为身份验证提供程序的文档

2)#704 - 将一个useNonce属性添加到ServerConfiguration中,以指示IdP是否将nonce值接受到其请求中.

所以我被困住了.2015年4月谷歌将关闭Open ID身份验证.

一些相关链接:

1) https://support.google.com/accounts/answer/6135882

2) https://www.tbray.org/ongoing/When/201x/2014/03/01/OpenID-Connect

3) https://github.com/mitreid-connect

4) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/blob/master/openid-connect-client/src/main/java/org/mitre/openid/connect/client/OIDCAuthenticationFilter.java

5) https://github.com/mitreid-connect/simple-web-app

6) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/blob/master/openid-connect-client/src/main/java/org/mitre/openid/connect/client/service/impl/PlainAuthRequestUrlBuilder.java

7) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues/726

8) https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/pull/704


2015-02-18更新

功能性最近被添加到mitreid-connect的开发分支中以禁用nonce - 因此使Google的OIDC服务器感到高兴.值得庆幸的是,mitreid-connect还提供了一些与Google互操作的指导.不幸的是,Maven中心尚未提供"nonceEnabled"更改,但希望很快就会改变.

ste*_*eve 3

AFAIK,没有干净、简单的 Spring Security 从 OpenID 迁移到 OpenID Connect 身份验证的方法。使用 Spring Security 实现 OpenID 身份验证非常简单<openid-login/>,但没有 OpenID Connect 的类似方法。

\n\n

MITREid替代方案仍在开发分支上,在 Maven Central 上不可用,因此不是候选方案。

\n\n

在评论中,Chuck Mah 指出了如何实现 Openid connect 和 Spring Security,其中 Romain F. 提供了示例代码

\n\n

Romain 的示例代码为我指明了正确的方向。鉴于时间已经不多了,我采用了 romain 的方法,即编写一个自定义 Spring Security AuthenticationFilter,它使用 spring-security-oauth2 来查询 oauth2 api userinfo 端点(对于 Google 来说是https://www .googleapis.com/oauth2/v2/userinfo)。假设是,如果我们能够成功查询 userinfo 端点,则用户已成功通过身份验证,因此我们可以信任返回的信息 - 例如用户的电子邮件地址。

\n\n

当我第一次开始学习 OpenID Connect 时, \xe2\x80\x9c id 令牌\xe2\x80\x9d 似乎是中心概念。但是,浏览 spring-security-oauth2 源代码,它似乎被忽略了。这就引出了一个问题,如果我们可以在没有 ID 令牌的情况下进行身份验证(通过简单地查询 oauth2 userinfo 端点),那么 ID 令牌的意义是什么?

\n\n

一个极简的解决方案 - 我更喜欢 - 会简单地返回一个经过验证的 ID 令牌。无需查询用户信息端点。但是 Spring Security 身份验证过滤器的形式不存在这样的解决方案。

\n\n

我的 web 应用程序不是像 romain 那样的 spring-boot 应用程序。spring-boot 在幕后做了很多配置。以下是我一路上遇到的一些问题/解决方案:

\n\n
    \n
  1. 问题:HTTP 状态 403 - 未找到预期的 CSRF 令牌。您的会话已过期吗?

    \n\n
      \n
    • 解决方案:java配置:httpSecurity.csrf().disable()
    • \n
  2. \n
  3. 问题:HTTP 状态 500 - 创建名称为“scopedTarget.googleOAuth2RestTemplate”的 bean 时出错:作用域“session”对于当前线程不活动;

    \n\n
      \n
    • 解决方案: java config: OAuth2RestTemplate 不需要是会话范围的(OAuth2ClientContext 已经是会话范围的,这就是必需的)
    • \n
  4. \n
  5. 问题:HTTP 状态 500 - 创建名为“scopedTarget.oauth2ClientContext”的 bean 时出错:作用域“session”对于当前线程不活动;

    \n\n
      \n
    • 解决方案:web.xml:添加RequestContextListener
    • \n
    • 解释:因为 oauth2ClientContext 会话范围 bean 是在 Spring MVC DispatcherServlet 范围之外访问的(它是从 OpenIdConnectAuthenticationFilter 访问的,它是 Spring Security 过滤器链的一部分)。
    • \n
    \n\n
    \n<监听器>\n <监听器类>org.springframework.web.context.request.RequestContextListener</监听器类>\n</监听器>\n
  6. \n
  7. 问题:org.springframework.security.oauth2.client.resource.UserRedirectRequiredException:需要重定向才能获得用户批准。

    \n\n
      \n
    • 解决方案:web.xml:立即添加过滤器定义在 springSecurityFilterChain 之前
    • \n
    \n\n
    \n<过滤器>\n <过滤器名称>oauth2ClientContextFilter</过滤器名称>\n <过滤器类>org.springframework.web.filter.DelegatingFilterProxy</过滤器类>\n</过滤器>\n<过滤器映射>\n <过滤器名称>oauth2ClientContextFilter</过滤器名称>\n <url 模式>/*</url 模式>\n</过滤器映射>\n
  8. \n
\n\n

不幸的是,OpenID Connect 不允许我们仅请求email范围。\n当我们的用户使用 OpenID 进行身份验证时,他们会看到一个同意屏幕,例如“webapp 希望查看您的电子邮件地址”,他们对此感到满意。现在,我们必须请求范围,openid email从而产生一个同意屏幕,要求用户与我们分享他们的整个公开个人资料……我们确实不需要或不想要……而且用户对这个同意屏幕不太舒服。

\n