Spring Security和Google OpenID Connect迁移

时间:2014-12-10 18:49:21

标签: spring-security google-oauth google-openid openid-connect

问题:

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

2)有没有办法 - 无论是从MITREid方面还是在Google帐户方面 - 都可以让MITREid OpenID Connect身份验证过滤器与Google的OpenID Connect服务配合使用?

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

详情:

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

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

  

重要提示:Google帐户的OpenID2将于4月份消失   20,2015。

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

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

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

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

  

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

接下来,我尝试将自己的MITREid AuthRequestUrlBuilder接口实现插入到MITREid配置中。我的实现和MITREid实现之间的唯一区别是我发送nonce。

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

  

身份验证失败:ID令牌不包含随机数声明

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

// 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.");
}

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

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

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

2)#704 - 在ServerConfiguration中添加一个useNonce属性,以指示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还提供了一些guidance on interoperating with Google。 不幸的是,Maven中心尚未提供“nonceEnabled”更改,但希望很快就会改变。

1 个答案:

答案 0 :(得分:3)

AFAIK,从OpenID到OpenID Connect身份验证没有干净简单的Spring Security迁移。使用完整记录的<openid-login/>实现使用Spring Security的OpenID身份验证是直截了当的,但OpenID Connect没有模拟。

MITREid alternative仍然在开发分支上,在Maven Central无法使用,因此不是候选人。

在评论中,Chuck Mah指向How to implement Openid connect and Spring Security,其中Romain F.提供sample code

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

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

一个极简主义的解决方案 - 我更喜欢 - 只会返回一个经过验证的ID令牌。不需要查询userinfo端点。但是,没有以Spring Security身份验证过滤器的形式存在此类解决方案。

我的webapp不是像罗曼那样的弹簧启动应用程序。 spring-boot在幕后做了很多配置。以下是我在此过程中遇到的一些问题/解决方案:

  1. 问题:HTTP状态403 - 未找到预期的CSRF令牌。你的课程到期了吗?

    • 解决方案:java config:httpSecurity.csrf()。disable()
  2. 问题:HTTP状态500 - 创建名称为“scopedTarget.googleOAuth2RestTemplate&#39;:范围&#39;会话&#39;当前线程无效;

    • 解决方案:java配置:OAuth2RestTemplate不需要是会话作用域的(OAuth2ClientContext已经是会话范围的,并且所有这些都是必要的)
  3. 问题:HTTP状态500 - 创建名称为&#39; scopedTarget.oauth2ClientContext&#39;:范围&#39;会话&#39;当前线程无效;

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

    • 解决方案:web.xml:立即添加过滤器定义PRECEEDING springSecurityFilterChain
    <filter>
        <filter-name>oauth2ClientContextFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>oauth2ClientContextFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
  5. 不幸的是,OpenID Connect不允许我们仅请求email范围。 当我们的用户使用OpenID进行身份验证时,他们会看到一个同意屏幕,例如&#34; webapp希望查看您的电子邮件地址&#34;他们很舒服。现在我们必须请求范围openid email,这会导致同意屏幕要求用户与我们分享他们的整个公开个人资料...我们真的不需要或不想...而且用户不太满意同意屏幕。