全栈工程师通往架构师之路

Shibboleth-IdP 的 OAuth2 对接方案详解

2020-02-18  本文已影响0人  freedomkk_qfeng

背景

Shibboleth 是一个支持 SAML2.0 的开源 IdP 服务器。

SAML2.0 是一个联邦式认证的标准,简单来说就是能够让应用方——也就是资源提供者(Service Provider,简称 SP)与任意的机构内部认证——也就是身份提供者(Identity Provider)对接时,能够均采用相同的协议标准。这显然能够简化集成,像 AWS,Azure 等云服务商都支持 SAML2.0 方式的机构账号对接。同时这种简化也促进了资源的共享,并形成了各式各样的身份联盟,比如中国的 CARSI[1],澳大利亚的 AAF[2],瑞士的 SWITCHaai[3] 等等,并且通过 eduGAIN[4] 将这些联盟连接起来。

Shibboleth 除了支持 SAML 以外,他在 IdP3 开始支持 CAS 协议[5],并且计划在 IdP4 开始引入 OpenID Connect ,然后在 IdP5 开始稳定支持 OpenID Connect 说实话这是一个槽点(另一个槽点是 CAS 也开始支持 SAML,你说这两拨人真是。。。)。然而如果我们要提供 CAS/OAuth2/OpenID Connect 服务的话,Shibboleth 显然不是优先的选项,SAML2.0 才是选择他的目的。好在 Shibboleth 支持通过一些外部插件的模式来进行认证[6],而 Unicon/shib-cas-authn3[7]是一个集成 CAS[8] 和 Shibboleth 的插件。OAuth2 的集成即基于此插件修改实现。

插件版本

由于 Shibboleth IdP 在 3.4.3 之后修改了一个内部的 API 实现,因此插件版本割裂为 3.3.0 和 3.2.3 两个版本。3.3.0 插件仅支持 Shibboleth IdP 3.4.6,而 3.2.3 仅支持 IdP 3.4.3。OAuth2 插件基于 shib-cas-authn3 插件的 3.2.3 版本修改,暂时不支持 IdP 3.4.6。

修改思路

OAuth2 本身只是授权协议,但是通常我们会将其与认证结合使用。因此包含了认证的 OAuth2 Server 可以与 CAS Server 进行对比。先看流程部分

步骤 CAS OAuth2 差异
1 回调到 CAS 认证 请求授权码,通常回调至认证 相对一致
2 认证完成,获得 ticket 认证完成,获得 code 相对一致
3 code 更换 token OAuth 独有
4 校验 ticket 并获取用户属性 使用 token 调用用户属性接口 相对一致
5 refresh token 可以刷新 token OAuth 独有

可以看到,不考虑 refresh token,把 OAuth 的第二步和第三步连接起来,OAuth 在流程上是可以和 CAS 保持一致的,这意味着插件可以不用进行伤筋动骨的修改,只需要针对性的微调即可。

其他差异:

与 CAS 不同,OAuth2 客户端在使用 code 更换 token 时,还需要附带自己的 redirect_uri,并且 OAuth2 服务端根据标准应该要检验两个 redirect_uri 是否一致。而 Shibboleth IdP 会根据 uri 中的 conversation=e1s1 来区分会话,比如 conversation=e1s1conversation=e1s2 。因此在集成中,IdP 的 redirect_uri 必须动态判定的,不能和 CAS 服务一样静态的指定 /cas/login 来解决。

另一个问题是用户名,对于 CAS 协议而言,用户名是一个标准的字段,他和属性的释放是区分开的。例如这个示例里,用户名已经由 <cas:user>字段标记出来,属性则包含在<cas:attributes>下面:

<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
   <cas:authenticationSuccess>
     <cas:user>username</cas:user>
     <cas:attributes>
       <cas:firstname>John</cas:firstname>
       <cas:lastname>Doe</cas:lastname>
       <cas:title>Mr.</cas:title>
       <cas:email>jdoe@example.org</cas:email>
       <cas:affiliation>staff</cas:affiliation>
       <cas:affiliation>faculty</cas:affiliation>
     </cas:attributes>
     <cas:proxyGrantingTicket>PGTIOU-84678-8a9d...</cas:proxyGrantingTicket>
   </cas:authenticationSuccess>
 </cas:serviceResponse>

而 CAS 插件会讲用户名作为 principalname 传递给 shibboleth,因此修改后的 OAuth2 必须也找到一个唯一确定的用户名字段来作为 principalname,这样才能复用原本 CAS 插件的很多功能。

因此这就引出了第三个问题,属性接口的标准。这实质上是 CAS 协议和 OAuth2 协议的核心分歧。OAuth2 本质上是一个授权协议,他的所有规范都是针对授权过程的(怎么获取 token )对于资源接口没有规定。而 CAS 是一个认证协议,他在认证返回的属性上有很明确的规范。因此这里,我们必须人为的给 OAuth2 Server 返回人员属性的接口进行规定。而这个规定实际上就可以直接参照 OpenID-Connect[9] 内关于 userinfo endpoint 的规范。例如这样的一个返回中,sub 是必须存在的字段,作用类似于 CAS 协议中的 <cas:user>,其他则是可选的,类似于 CAS 协议中 <cas:attributes> 下层中的那些属性

  HTTP/1.1 200 OK
  Content-Type: application/json

  {
   "sub": "248289761001",
   "name": "Jane Doe",
   "given_name": "Jane",
   "family_name": "Doe",
   "preferred_username": "j.doe",
   "email": "janedoe@example.com",
   "picture": "http://example.com/janedoe/me.jpg"
  }

当然这只是一个建议 。在插件中,我们通过配置 shibcas.oauth2principalname = sub 来指定 principalname 所指代的属性字段 ,由用户来选择。接口必须避免层级嵌套,以确保插件能够直接的获取到对应的属性。

最终的 OAuth2 插件源码地址在 https://github.com/shanghai-edu/shib-cas-authn3,选择 tag 3.2.4-oauth 。插件代码基于北京大学赖清楠老师的版本进一步修改优化,特别感谢北京大学 CARSI 项目组团队的前期工作。

插件安装文档详见 CARSI-WiKiSEAC-Document

3.3.0 的 OAuth 版本修改正在工作中,To Be Continued ~~~

实践

常见的坑

实际上正是由于 OAuth2 缺乏 userinfo 的规范,导致 OAuth2 协议对接时,通常需要少量的代码层定制。这反过来导致了一些开发商在提供 OAuth2 产品时的随意和不规范。以下是我碰到过的几个反面例子:

快速测试

oauth-server-lite

oauth-server-lite[13] 是一个轻量级的 OAuth2 服务器,认证部分对接 LDAP ,并将 LDAP 的属性映射为 userinfo 接口。因此可用于 IdP 的 OAuth2 对接测试。

oauth-server-lite 的认证部分支持验证码和IP地址封禁,以对抗暴力破解。因此也将其直接和 IdP 打包在一起部署,作为 IdP 的安全加固手段之一应用。

oauth-server-lite 的 /oauth/v1/userinfo 接口实现了 OpenID-Connect 的规范,它会将用户名作为 sub 字段默认插入,并将 ldap 返回的属性作为其他字段输出。ldap 的多值部分以 ; 连接为字符串,例如:

{
  "cn": "小冯冯", 
  "uid": "11116666", 
  "memberOf": "教职工", 
  "mail": "qfeng@exampe.org", 
  "sub": "11116666"
}

oauth-server-lite 的事情,留到下回再说吧

以上

参考文献

[1] CERNET Authentication and Resource Sharing Infrastructure
[2] Australian Access Federation
[3] SWITCH Authentication and Authorization Infrastructure
[4] eduGAIN
[5] Shibboleth Implemented Protocols and Profiles
[6] Shibboleth RemoteUserAuthnConfiguration
[7] A Shibboleth IdP v3.X plugin for authentication via an external CAS Server
[8] CAS Enterprise Single Sign-On
[9] OpenID Connect Core 1.0 incorporating errata set 1
[10] OAuth2 RFC
[11] 小米开发平台
[12] 微信开发平台
[13] shanghai-edu/oauth-server-lite

转载授权

CC BY-SA

上一篇下一篇

猜你喜欢

热点阅读