OIDC认证

介绍云平台OIDC认证对接

基本原理

OIDC为标准的SSO认证协议,协议标准参见:https://openid.net/specs/openid-connect-basic-1_0.html

OIDC主要定义了用户浏览器,认证提供方(IDP)和服务提供方(SP)之间基于web/http交换的标准接口协议,实现用户基于浏览器,以IDP为统一登录入口,实现用户以在IDP注册的身份实现对SP提供的内容的认证访问。

OIDC定义的用户认证登录流程如下图所示,该流程从未登录的用户浏览器访问SP内容开始,以用户浏览器登录并获得请求的内容结束。

接口定义

该流程中,IDP和SP需要提供如下接口:

接口提供者访问者实现功能
Auth接口IDP用户浏览器用户浏览器携带SP的redirect_uri, client_id等信息访问IDP的auth URL,开始用户在IDP的认证流程
Redirect接口SP用户浏览器用户浏览器在IDP完成认证后,被IDP重定向到SP的Redirect接口,通过该接口,浏览器将从IDP获得的临时token提交给SP
Token接口IDPSP后端SP后端获得用户浏览器从IDP携带的token后,调用IDP的token接口,获得访问userinfo的AccessToken
Userinfo接口IDPSP后端SP后端获得AccessToken后,调用IDP的userinfo接口,获得登录用户的认证信息,包括用户ID,名称等
Logout接口IDP用户浏览器用户在SP页面登出时,重定向到IDP的logout页面清除用户在IDP的登录session

Auth接口

Auth接口由IDP提供给用户浏览器访问,触发用户在IDP的认证流程。该接口的访问形式如下:

GET /authorize?
    response_type=code
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
    &scope=openid%20profile
    &state=af0ifjsldkj HTTP/1.1
  Host: server.example.com

该接口的参数含义解释如下:

参数含义
response_type总是为code
client_idSP在IDP注册的client_id
redirect_uriSP在IDP注册的回调URL,认证成功后,IDP将重定向用户浏览器到该URL
scope认证获取信息的访问,由IDP定义,一般为user profile等
state认证之前的状态信息,例如用户访问的页面URL等

Redirect接口

该接口由SP提供,用户浏览器访问IDP Auth接口并认证成功后,将被重定向到该接口,以想SP通知认证的token。该接口的访问形式如下:

GET /cb?
    code=SplxlOBeZQQYbYS6WxSbIA
    &state=af0ifjsldkj
Host: client.example.org

该接口的参数含义解释如下:

参数含义
code用户在IDP认证成功后,获得的临时认证code
state用户访问IDP Auth接口时携带的state参数内容,用于SP恢复用户认证前的状态

Token接口

该接口由IDP提供,被SP访问,用于获取访问userinfo的token,该接口的访问形式如下:

  POST /token HTTP/1.1
  Host: server.example.com
  Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
  Content-Type: application/x-www-form-urlencoded

  grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
    &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

该接口的参数含义解释如下:

参数含义
grant_type总是为authorization_code
code用户浏览器提交给SP的从IDP获得的code
redirect_uriSP在IDP注册的回调URL

请求该接口需要认证,认证参数为:

Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW

其中,认证信息有SP在IDP注册的client_id和secret编码组成,按如下方式编码:

Base64Encode(URLEncode(client_id)+”:”+URLEncode(secret))

该接口响应形式如下:

  HTTP/1.1 200 OK
  Content-Type: application/json
  Cache-Control: no-cache, no-store
  Pragma: no-cache

  {
   "access_token":"SlAV32hkKG",
   "token_type":"Bearer",
   "expires_in":3600,
   "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
   "id_token":"eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso"
  }

各个参数含义解释如下:

参数含义
access_token用户在IDP认证成功后,获得的临时认证code
token_type总是为bear
expires_in改access_token的超时时间
refresh_token刷新access_token的token,没有用
id_token用户信息的JWT token,没有用

Userinfo接口

该接口由IDP提供,向SP提供用户的信息。该接口的访问形式如下:

  GET /userinfo HTTP/1.1
  Host: server.example.com
  Authorization: Bearer SlAV32hkKG

其中,请求Header的Authorization的Bearer为上一步获得的access_token。

该接口返回数据格式在协议中未定义。在{<oem_name>}}场景中,该接口返回数据为包含用户信息的json,包含字段以及字段含义如下:

字段名称类型说明
dataobject用户信息的json object
+allow_web_consoleboolean是否支持web控制台登录
+created_atdatetime用户的创建时间
+displaynamestring用户的显示名称
+domainobject用户所在的域
++idstring域id
++namestring域的名称
+domain_policies[string]当前用户的域级别权限
+emailstring用户的邮箱
+enable_mfaboolean是否启用MFA
+ enable_quota_checkBoolean是否启用配额
+ enabledBoolean是否启用
+failed_auth_countInteger改用连续认证失败的次数
+idString用户的ID
+idpsObject用户关联的外部认证源的用户信息
++idpString认证源名称
++idp_dirverString认证源的类型,如oidc
++idp_entity_idString用户在该认证源对应的用户的外部ID
++idp_idString认证源的ID
++templateString认证源的模板
+is_localString该用户是否为本地SQL维护的用户
+is_system_accountBoolean该用户是否为系统账号(服务账号)
+last_active_atdatetime上次用户登录时间
+last_login_ipIpaddr上次用户登录IP
+last_login_sourcestring上次用户登录来源
+mobileString手机号
+nameString用户名
+need_reset_passwordBoolean该用户是否需要重置密码
+non_default_domain_projectsBoolean是否开启三级权限
+projectDomainString该用户当前所在项目的归属域名称
+projectDomainIdString该用户当前所在项目的归属域ID
+projectIdString该用户当前所在项目ID
+projectNameString该用户当前所在项目名称
+project_metaObject该用户当前所在项目的标签
+project_policies[string]该用户的项目级别权限
+projectsArray该用户加入的所有项目的列表
++domainString此项目的归属域
++domain_idString此项目的归属域ID
++idString此项目的ID
++nameString此项目的名称
++rolesObject该用户在此项目的角色列表
+++idString角色ID
+++nameString角色名称
++system_capableBoolean该用户在此项目是否具备系统级别权限
++system_policies[string]该用户在此项目的系统级别权限列表
++domain_capableBoolean该用户在此项目是否具备域级别权限
++domain_policies[string]该用户在此项目的域级别权限列表
++project_capableBoolean该用户在此项目是否具备项目级别权限
++project_policies[string]该用户在此项目的项目级别权限列表
+rolesString该用户在当前项目的角色列表
+system_policies[string]该用户的系统级别权限

Logout接口

该接口由IDP提供。当用户在SP发起退出时,SP重定向用户浏览器到IDP的logout接口清除用户浏览器在IDP的登录session。具体接口定义于https://openid.net/specs/openid-connect-rpinitiated-1_0-02.html。 该接口可以用GET或POST方法请求,请求路径一般为:

GET /api/v1/auth/oidc/logout

接口参数:

参数含义
post_logout_redirect_uri用户浏览器在IDP清除session成功后,重定向到指定URI
state状态信息,浏览器重定向到post_logout_redirect_uri是将携带该state
id_token_hint没有用
logout_hint没有用
client_id没有用
ui_locales没有用

对接步骤

和云联壹云OIDC对接一般需要如下步骤:

  1. 在云联壹云申请OIDC对接的认证信息,主要为client_id和secret。申请位置在用户登入的右上角用户此单的“访问凭证”,选择“OpenID Connect/OAuth2”页签,点击“创建”。输入当前OIDC应用的回调URL。创建成功后,可以在该页签的列表查看所有的OIDC认证信息。其中,和云联壹云对接的OIDC的认证接口的信息可以在该页签查看:

  1. 配置第三方应用使用OIDC认证。如果第三方应用还未实现和OIDC对接的,请参考协议和本文档实现对接。

应用举例(Grafana)

Grafana支持以OIDC认证源实现SSO登录,{<oem_name>}}可以作为Grafana的OIDC认证源,Grafana需要做如下配置。

配置文件

下面仅列出了认证需要的配置项。其中,Grafana会在认证响应中查找用户的email字段,当且仅当用户email的域名在allowed_domains中,该用户才认为是有效的。allow_sign_up需要为true,这样才会自动会用户新建一个本地用户。

[auth.anonymous]
enabled = true
org_role = Viewer
[auth.generic_oauth]
enabled = true
client_id = fcc98ad5a22a4de5831cf806980ffb75
client_secret = SzQyVEtaelZFMkZFbmJOeDRTWmh3Y0JKNFNzTlhtekM=
scopes = user
auth_url = https://www.gzgzyun.com:8888/api/v1/auth/oidc/auth
token_url = https://www.gzgzyun.com:8888/api/v1/auth/oidc/token
api_url = https://www.gzgzyun.com:8888/api/v1/auth/oidc/user
allowed_domains = gzgzyun.com
allow_sign_up = true
role_attribute_path = projectName == 'system' && contains(roles, 'admin') && 'Admin' || 'Editor'
[server]
root_url = https://grafana.gzgzyun.com
domain = grafana.gzgzyun.com
enforce_domain = true

环境变量

grafana容器启动环境变量:设置这个变量GF_AUTH_GENERIC_OAUTH_TLS_SKIP_VERIFY_INSECURE为true之后,才会忽略验证token时的TLS错误。

- name: GF_AUTH_GENERIC_OAUTH_TLS_SKIP_VERIFY_INSECURE
  value: 'true'

要求

user必须有email的属性