5 分钟部署一个 OAuth2 服务并对接 Shibboleth-IdP 3.4.6

前言

这还是一个标题党。

OAuth2 现在已经是开放授权协议的事实标准,你可以看到几乎所有的 xxx 开放平台均采取的 OAuth2 协议来进行授权。而在 Authorization Code 模式的基础上结合 JWT ,标准化的 userinfo endpoint 和服务发现,就成了 OpenID-Connect。当然即便不加上这些限定,OAuth2 在 Authorization Code 模式下,也通常被用作统一身份认证的解决方案提供给用户。而由于 OAuth2 与 CAS 不同,缺乏 Apereo CAS 这样的重量级产品来对标(话说回来,Apereo CAS 现在自己就支持 OAuth2 来着)。于是市场上的 OAuth2 实现可谓群魔乱舞,槽点一时难以穷尽。

个人建议,在选取 OAuth2 产品时,务必通过 oauth playground 进行测试,以验证协议实现的标准性,避免将来踩坑。而如果需要自己临时起一个 OAuth2 服务做测试的话嘛~~~

是的,搭一个 OAuth 服务器 5 分钟就够了。

Apereo CAS - OAuth2

是的,Apereo CAS 现在也支持 OAuth2 协议了,所以如果你已经按照 15 分钟部署一个 CAS 服务并对接 Shibboleth-IdP 3.4.6 的路程部署好了 CAS 服务的话,那么只需要略微的调整,就可以让他支持 OAuth2 了,5 分钟足矣。

下文假定已经安装好了 shibboleth-idp-3.4.6 和 cas 6.1 ,并使用 httpd 方式代理发布。

  1. 修改 build.gradle ,在 dependencies 内进一步增加 oauth-webflow 的编译依赖
dependencies {
    // Other CAS dependencies/modules may be listed here...
     compile "org.apereo.cas:cas-server-support-json-service-registry:${casServerVersion}"
     compile "org.apereo.cas:cas-server-support-ldap:${casServerVersion}"
     compile "org.apereo.cas:cas-server-support-oauth-webflow:${project.'cas.version'}"
}
  1. cas-overlay-template/etc/cas/services/ 目录内新增 oauth-1000.json 文件,注册我们的 oauth 服务
{
  @class : org.apereo.cas.support.oauth.services.OAuthRegisteredService
  clientId: google
  clientSecret: google
  serviceId: ^https://developers.google.com/.*
  name: OAuthService
  id: 1000
  supportedGrantTypes: [ "java.util.HashSet", [ "authorization_code" ] ]
  supportedResponseTypes: [ "java.util.HashSet", [ "code" ] ]
}

设置好 clientIdclientSecret,设置好允许的 serviceId,也就是 redirect_uri

  1. 修改 cas-overlay-template/etc/cas/config/cas.properties,增加这条配置。
cas.authn.oauth.userProfileViewType=FLAT

此处默认的值是 NEST,此时 userinfo 的中,属性部分是带 attributes 的子结构的, 如果是 FLAT 的话,则会去掉结构铺平。以下示例引用自 Apereo CAS 官网

# Nested
{
  "id": "casuser",
  "attributes": {
    "email": "casuser@example.org",
    "name": "CAS"
  },
  "something": "else"
}
# FLAT
{
  "id": "casuser",
  "email": "casuser@example.org",
  "name": "CAS",
  "something": "else"
}

Shibboleth-IdP 的 OAuth2 对接需要去掉结构,所以我们使用 FLAT 模式

  1. 好啦,重新编译 docker 并运行,OAuth2 服务已经搞定了,去 oauth playground 测试一下吧。
  2. Endpoints
    Authorization endpoint : /cas/oauth2.0/authorize
    Token endpoint : /cas/oauth2.0/accessToken
    Userinfo endpoint : /cas/oauth2.0/profile

oauth-server-lite

如果没有 CAS 部署的前序工作的话,5 分钟的时间可能不太够。但是既然 FLAG 已经立好了。。。我们可以用 oauth-server-lite 来快速的构建一个 oauth 服务。

  1. 先装个 redis,这是唯一的依赖了
$ yum install epel-release
$ yum install redis
$ systemctl start redis
$ systemctl enable redis
  1. 下载 oauth-server-lite 并解压。他是 go 语言写的,改下配置直接就可以跑了
$ mkdir oauth-server-lite
$ cd oauth-server-lite
$ wget https://github.com/shanghai-edu/oauth-server-lite/releases/download/v0.3.0/oauth-server-lite-0.3.tar.gz
$ tar -zxvf oauth-server-lite-0.3.tar.gz
$ mv cfg.example.json cfg.json
  1. 修改配置文件
{
    "log_level": "info", # info/warn/debug 三种
    "db": {
        "sqlite":"sqlite.db", # 只要不为空,则使用 sqlite 模式,存储到字段中的 sqlite 文件中
        "mysql": "root:password@tcp(127.0.0.1:3306)/oauth?charset=utf8&parseTime=True&loc=Local", # 使用 mysql 模式时的数据库连接参数
        "db_debug": false # true 时会输出详细的 sql debug
    },
    "redis": {
        "dsn": "127.0.0.1:6379",
        "max_idle": 5,
        "conn_timeout": 5, # 单位都是秒
        "read_timeout": 5,
        "write_timeout": 5,
        "password": ""
    },
    "redis_namespace":{ # redis key 的命名空间,保持默认即可
        "oauth":"oauth:",
        "cache":"cache:",
        "lock":"lock:",
        "fail":"fail:"
    },
    "ldap": {
        "addr": "ldap.example.org:389",
        "baseDn": "dc=example,dc=org",
        "bindDn": "cn=manager,dc=example,dc=org",
        "bindPass": "password",
        "authFilter": "(&(uid=%s))",
        "attributes": ["uid", "cn", "mail"], # ldap 返回的属性。这部分会映射为 userinfo 的接口。如果留空则返回全部属性
        "tls":        false,
        "startTLS":   false
    },
    "http": {
        "listen": "0.0.0.0:18080",
        "manage_ip": ["127.0.0.1"], # 管理接口的授信 ip
        "x-api-key": "shanghai-edu", # 管理接口的 api key
        "session_options":{ # session 参数
            "path":"/",
            "domain":"idp.example.org", # 必须与实际域名匹配
            "max_age":7200,
            "secure":false,
            "http_only":false
        },
        "max_multipart_memory":100
    },
    "max_failed":5, # 最大密码错误次数
    "failed_intervel":300, # 密码错误统计的间隔时间
    "lock_time":600, # 锁定时间
    "access_token_expired":7200, # oauth access token 有效期,单位是秒
    "old_access_token_expired":300, # 新的 oauth access token 生成时,老 token 的保留时间
    "refresh_token_expired_day":365, # refresh token 的有效期,单位是天
    "code_expired":300 # authorization_code 的有效期,单位是秒
}

配置文件的示例。考虑到 5 分钟还是有点紧张,我们只挑重要的部分修改。把 ldap 部分的配置修改为实际的 ldap 参数,把 http->session_options->domain 修改为实际的服务器域名。然后执行 ./control start 运行

  1. httpd 加一段反向代理,发布 oauth 服务
        ProxyPreserveHost On
        RequestHeader set X-Forwarded-Proto https
        RemoteIPHeader X-Forwarded-For

        ProxyPass "/resource/" "http://localhost:18080/resource/"
        ProxyPass "/oauth/" "http://localhost:18080/oauth/"
        ProxyPass "/user/" "http://localhost:18080/user/"
  1. ouath-server-liteclient 信息储存在数据库中。我们刚才使用了默认的 sqlite 模式,因此在首次启动后,他会自动创建 sqlite.db 文件并初始化表结构。现在我们调用管理接口生成 client。如下所示,我们创建了一个授权域名是 developers.google.comclient。然后就用它去 oauth playground 测试吧。
$ curl -H "X-API-KEY: shanghai-edu" -H "Content-Type: application/json" -d "{\"grant_type\":\"authorization_code\",\"domain\":\"developers.google.com\"}" http://127.0.0.1:18080/manage/v1/client
{"client_id":"8455e95a63d682bb","client_secret":"385a8174dd0799e220a8407f8ca6e8a9","grant_type":"authorization_code","domain":"developers.google.com","white_ip":"","scope":"Basic","description":""}
  1. endpoints
    Authorization endpoint : /oauth/v1/authorize
    Token endpoint : /oauth/v1/token
    Userinfo endpoint : /oauth/v1/userinfo

对接 Shibboleth-IdP 3.4.6

其实 3.4.6 之后,由于新版插件均采用标准的 Externel 模式运行,因此 IdP 的 OAuth2 对接和 CAS 对接基本是完全一致的 —— 实际上 OAuth2 插件本来就是在 CAS 插件的基础上改的。有变化的地方仅 2 处。

  1. 引入的 jar 包替换为 shib-cas-authenticator-3.3.0-oauth.jar
  2. idp.properties 中调整为 OAuth2 相关的配置。唯一需要注意的是,shibcas.oauth2principalname 应该配置为用户资源属性接口中,代表用户名的字段。例如我们使用 Apereo CASOAuth2 时,这里应该设置为 shibcas.oauth2principalname = id,而使用 oauth-server-lite 时,则可以设置为 shibcas.oauth2principalname = sub。当然,这里因为用的是同一个 ldap,因此设置为 shibcas.oauth2principalname = uid 显然也都是可以的。总之这个字段存在就行。

更多细节可以关注 上海教育认证中心-IdP-Oauth2 对接 中的配置说明。

以上

参考文献

  1. oauth playground
  2. CAS: OAuth-OpenId-Authentication
  3. shanghai-edu/shib-cas-authn3/tree/3.3.0-oauth
  4. shanghai-edu/oauth-server-lite
  5. 上海教育认证中心-IdP-Oauth2 对接

转载授权

CC BY-SA

搬迁声明

我的博客即将同步至 OSCHINA 社区,这是我的 OSCHINA ID:小冯冯,邀请大家一同入驻:https://www.oschina.net/sharing-plan/apply

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342