IAM2 OAuth 2.0 Token Exchange
这份笔记主要记录 OAuth 2.0 协议扩展用于授权与委托时的规范与个人理解。
1. Delegation 与 Impersonation
安全令牌服务(STS)是一种 server 能够验证提供给它的安全令牌,并据此签发新安全令牌的服务,它让 client 能够在异构环境或跨安全域的情况下,为资源获取合适的访问凭证。
STS 的一个常见用途是允许资源服务器 A 代表请求用户 B 调用后端服务 C,这时可能涉及到两种情形:
- 希望A使用自己的凭据访问C,并附上某种形式的标注说明A是代表B行事(委托语义)
- 希望授予A一个对C的有限访问凭据,但仍将B标识为被授权实体(冒充语义)
委托和冒充这两种语义在其他涉及多个参与者的场景中也可能是有用的概念。
总结:
- 委托(Delegation):即 A 以自己的身份代表 B 行动
- 新生成的令牌需要包含原始令牌所有者和发起者的身份信息
- 冒充(Impersonation):即 A 在一定权限范围内以 B 的身份行动
- 新生成的令牌完全代表原始令牌所有者的身份,发起者身份不保留
2. Token Exchange Request and Response
2.1 Request
客户端通过使用 RFC6749 中 Section 4.5 定义的扩展授权类型机制,向授权服务器的令牌端点发起令牌请求,来申请安全令牌。
客户端身份验证是可扩展的,但是推荐不要省略客户端身份验证。因为,如果省略客户端身份验证,那么任何持有被泄露令牌的人都可以通过 STS 把这个令牌换成其他令牌。因此,客户端身份验证让 STS 可以做额外的授权检查,判断哪些实体被允许冒充其他实体或接受其他实体的委托。
客户端用 HTTP POST 方法,带着扩展授权类型,向令牌端点发起令牌交换请求。请求体使用 application/x-www-form-urlencoded 编码,其包含下列参数:
| 参数 | 是否必需 | 说明 |
|---|---|---|
grant_type | 必需 | 固定为 urn:ietf:params:oauth:grant-type:token-exchange,表示执行令牌交换。 |
resource | 可选 | 目标资源或服务的 URI,表示新令牌将用于访问哪个资源。可指定多个。 |
audience | 可选 | 目标服务的逻辑标识符,作用类似 resource,但不要求是 URI。可指定多个。 |
scope | 可选 | 请求新令牌具有的权限范围,多个权限以空格分隔。 |
requested_token_type | 可选 | 期望获得的令牌类型,例如 Access Token 或 JWT。未指定时由授权服务器决定。 |
subject_token | 必需 | 代表被代理主体身份的安全令牌,例如用户 Alice 的 Access Token。 |
subject_token_type | 必需 | subject_token 的令牌类型标识符。 |
actor_token | 可选 | 代表实际执行者身份的安全令牌,例如 Agent A 的身份令牌。 |
actor_token_type | 条件必需 | actor_token 的令牌类型标识符。提供 actor_token 时必须提供,否则不得提供。 |
2.2 Response
授权服务器对令牌交换请求的响应,就是令牌端点返回的普通 OAuth 2.0 响应,具体按 RFC6749 中 Section 5的规定来。
2.21 成功响应
如果请求有效,并且符合授权服务器的所有策略和其他条件,就构造一个成功的令牌响应:使用“application/json”媒体类型,把以下参数添加到HTTP响应的实体主体中,并返回HTTP 200状态码。
| 参数 | 是否必需 | 说明 |
|---|---|---|
access_token | 必需 | 授权服务器签发的新安全令牌,不一定是 OAuth Access Token。 |
issued_token_type | 必需 | 新令牌的类型标识符,例如 Access Token、JWT。 |
token_type | 必需 | 令牌的使用方式,例如 Bearer;不适用时使用 N_A。 |
expires_in | 推荐 | 新令牌的有效期,单位为秒,例如 1800 表示 30 分钟。 |
scope | 条件必需 | 新令牌实际授予的权限范围。如果与请求的范围相同则可省略,否则必须返回。 |
refresh_token | 可选 | 用于刷新访问凭证的令牌。令牌交换通常不返回,但特定场景下可以签发。 |
2.22 失败响应
-
无效请求:如果请求本身无效,或者subject_token或actor_token因任何原因无效,或根据策略不可接受,授权服务器必须按照 RFC6749 第5.2节的规定构造错误响应。error参数的值必须是invalid_request错误代码。
-
无效目标:如果授权服务器不愿或无法为resource或audience参数所指示的任何目标服务签发令牌,则应在错误响应中使用invalid_target错误代码。
授权服务器可以使用RFC6749第5.2节中讨论的error_description来包含有关错误原因的附加信息。
也可以酌情使用其他错误代码。
3. JWT
JWT(JSON Web Token)是一种紧凑的、适合在不同系统之间传递声明(Claims)的令牌格式,由 RFC 7519 定义。Claim(声明)是 JWT 中描述身份、权限、时间等信息的键值对。
常见的签名 JWT 采用 JWS Compact Serialization 格式:
Header.Payload.Signature| 组成部分 | 说明 |
|---|---|
| Header | 描述令牌类型、签名算法等信息 |
| Payload | 包含 JWT Claims,即令牌的具体声明 |
| Signature | 用于验证签名数据的完整性及签名者身份 |
例如,Header 可以是:
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-1"
}alg:签名算法。typ:令牌类型提示。kid:密钥标识,帮助验证方选择公钥。
Access Token 可以采用 JWT 格式,也可以采用不透明格式。此外,JWT 也可以采用 JWE 加密形式,而不局限于上述三段式的签名形式。
3.1 JWT 标准 Claims
| Claim | 英文名称 | 含义 |
|---|---|---|
iss | Issuer | 签发者,表示由谁签发 JWT |
sub | Subject | 主体,表示 JWT 所描述的身份主体 |
aud | Audience | 受众,表示 JWT 预期由哪些接收方处理 |
exp | Expiration Time | 过期时间,此时间起令牌不再有效 |
nbf | Not Before | 生效时间,在此之前不得接受令牌 |
iat | Issued At | 签发时间 |
jti | JWT ID | JWT 的唯一标识符,可辅助实现重放检测 |
其中,exp、nbf 和 iat 使用 NumericDate 格式,通常表现为 Unix 时间戳(以秒为单位)。
3.2 扩展 Claims
RFC 8693 §4 为 Token Exchange 场景定义并注册了以下四个 JWT Claims:
| Claim | 英文名称 | 含义 |
|---|---|---|
act | Actor | 标识当前代表主体执行操作的代理执行者 |
scope | Scopes | 表示令牌所关联的授权权限范围 |
client_id | Client Identifier | 标识申请该令牌的 OAuth 客户端 |
may_act | Authorized Actor | 声明有资格代表某个主体执行操作的一方 |
3.21 "act"
act 声明在 JWT 中提供了一种方式,用来表示发生了委托,并标识被授予权限的代理方。
act 声明的值是一个 JSON 对象,JSON 对象中的成员是用于标识该代理方的声明。构成 act 声明的这些声明用于标识代理方,说明当前由谁代表主体执行操作,并可能提供关于该代理方的附加信息。
act 的值是一个 JSON 对象,可以包含用于标识 Actor 的 Claims,例如 iss 和 sub。但不应该把 exp、nbf、aud 等令牌有效性声明放在 act 内部。
此外,act 支持嵌套,以表示多级委托关系:
{
"aud":"https://service26.example.com",
"iss":"https://issuer.example.com",
"exp":1443904100,
"nbf":1443904000,
"sub":"user@example.com",
"act":
{
"sub":"https://service16.example.com",
"act":
{
"sub":"https://service77.example.com"
}
}
}3.22 "scope"
scope 表示令牌具有的权限范围。多个 Scope 使用空格分隔。Scope 的具体名称和语义由授权服务器与资源服务器约定。
{
"aud":"https://consumer.example.com",
"iss":"https://issuer.example.com",
"exp":1443904177,
"nbf":1443904077,
"sub":"dgaf4mvfs75Fci_FL3heQA",
"scope":"email profile phone address"
}3.23 "client_id"
client_id 标识申请该令牌的 OAuth 客户端。
{
"aud":"https://consumer.example.com",
"iss":"https://issuer.example.com",
"exp":1443904177,
"sub":"user@example.com",
"client_id":"s6BhdRkqt3"
}3.24 "may_act"
may_act 用于声明某个主体有资格成为代理执行者。
{
"aud":"https://consumer.example.com",
"iss":"https://issuer.example.com",
"exp":1443904177,
"nbf":1443904077,
"sub":"user@example.com",
"may_act":
{
"sub":"admin@example.com"
}
}在 Token Exchange 中,STS 可以利用输入 subject_token 中的 may_act,判断当前客户端或 actor_token 所代表的主体是否允许执行委托。
参考
RFC 8693: OAuth 2.0 Token Exchange | RFC Editor
JSON Web Token (JWT)