ttps://medium.com/@robert.broeckelmann/saml2-vs-jwt-understanding-openid-connect-part-2-f361ca867baa
这篇文章继续我们对OpenID连接(OIDC)的讨论。我们来看看OIDC规范定义的三个身份验证流之一——授权代码授权流。
1、OIDC身份验证流
OAuth2定义了授权授权和扩展授权(Authorization Grants and Extension Grants),OIDC规范定义了认证流。概念是相似的。该规范定义了三个认证流;这些流的不同之处包括传递给OP的参数、响应的内容以及如何处理响应。对授权端点的请求(以及身份验证流详细信息)之间的区别是return_type参数。该参数有几个有效值,定义在OAuth2规范和OAuth2多响应类型规范之间:
Authorization Code Flow: code
Implicit Flow: id_token
Implicit Flow: id_token token
Hybrid Flow: code id_token
Hybrid Flow: code token
Hybrid Flow: code id_token token
那么,这一切意味着什么呢?当您在response_type参数中看到“code”值时,授权端点响应将返回授权代码。只要在response_type参数中包含了“id_token”,就会在响应中包含一个id_token。当response_type参数中包含“token”时,来自授权端点的响应中将包含一个access_token。这些细节会影响响应的结构,依赖方(RP、客户)(Relying Party (RP, Client))下一步采取什么处理步骤,以及可以处理什么用例,如下所示。请注意,
OIDC授权码流直接扩展了OAuth2授权码授权。OIDC隐式流和OIDC混合流是对OIDC授权码流的扩展。
OIDC定义的授权码response_type与OAuth2规范定义的同名response_type不同。
本文中使用的所有示例请求和响应都是OIDC规范中给出的示例的变体。
授权码流(OIDC v1.0规范,章节3.1):这是OAuth2授权码授权的OIDC版本。此流的response_type设置为“code”。这里给出的示例利用授权代码Grant中的所有可用功能来完成:
终端用户认证
中继方(客户端、应用程序)Relaying Party (Client, application)的身份验证(可选)。
中继方(RP) Relaying Party (RP)看不到最终用户的凭据(密码)
用户代理User Agent 看不到访问令牌或ID令牌Access Token or ID Token
SSO RP
获取多个访问令牌或多个范围访问令牌。
使用访问令牌对API提供者(资源服务器,Resource Server)进行API(资源)调用。
下面将遍历上图中的步骤。最终用户通过在web浏览器中输入网站地址或类似的操作(图中没有显示)来启动应用程序登录过程。然后浏览器(用户代理)向RP发送一个请求,RP拦截该请求并发现它不是经过身份验证的会话的一部分——同样,在图中也没有显示(规范没有涵盖这一部分)。
(1)身份验证请求
RP将用户代理重定向到OpenID提供者(OP)——步骤(A)。结果请求看起来像这样:
GET /oidc/authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
Host: server.example.com
identity provider (OP) 将重定向用户代理登录工作流是由OP -步骤(B)。身份验证是如何工作的详细信息不在OIDC规范的范围。我们称之为OIDC身份验证协议,但它没有定义如何验证用户的详细信息。这与SAML2 Web Browser SSO Profile的工作方式没有什么不同——用户的实际身份验证可以是各种各样的机制,这些机制依赖于身份提供者(OP)功能。身份验证工作流还可以包含一个检查,允许最终用户同意RP对其拥有的资源的访问(授权访问被授予Resource上的RP)。
(2)成功的身份验证响应
成功的身份验证后,OP将用户重定向回授权端点authorization endpoint ,使用会话跟踪信息集(可能是会话cookie的形式,依赖于实现)。授权端点将返回一个HTTP重定向(带有授权码)到RP URL,它看起来类似于以下步骤(C):
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
因此,用户代理向RP发送如下请求:
GET https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
(3)身份验证错误
如果在身份验证和同意阶段(或返回授权代码之前的任何其他阶段)发生错误,授权端点将返回类似如下的错误:
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
error=invalid_request
&error_description=
Unsupported%20response_type%20value
&state=af0ifjsldkj
(4)令牌的请求
此时,RP已经收到了授权代码,但还没有看到最终用户的密码(或其他凭据)。现在,RP需要从令牌端点获取访问令牌、ID令牌Access Token, ID Token和其他信息。因此,RP向令牌端点 token endpoint发送类似如下的请求——步骤(D):
POST /oidc/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=SplxlOBeZQQYbYS6WxSbIA&
redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb&
client_id=s6BhdRkqt3&
client_secret=blah_blah_blah_1234
client_secret参数只需要在RP是一个机密客户端时存在(就像一般的OAuth2授权码授予一样)。在OIDC规范第9节中描述了验证RP到令牌端点的替代方法;OAuth2规范也支持基本身份验证(它是首选的方法)。
(5)令牌响应
来自授权代码流的令牌端点 token endpoint 的响应类似于以下步骤(E)。
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
“access_token”: “SlAV32hkKG”,
“token_type”: “Bearer”,
“refresh_token”: “8xLOxBtZp8”,
“expires_in”: 3600,
“id_token”: “eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg”
}
(6)验证令牌
现在,ID Token(上面的id_token属性)必须根据OIDC规范的3.1.3.7节进行验证——步骤(F)——不要跳过这一部分,这会影响安全性。对于这个认证流,ID令牌 ID Token将包含一个at_hash(访问令牌散列) (Access Token hash) 属性,可以用来验证访问令牌;这是可选的,但推荐的步骤(G)。
在OIDC场景下,RP上使用ID Token进行认证,使用Access Token进行认证:
调用资源服务器(在我们的例子中是API提供者)
userinfo 端点处获取信息(可选)
这与oauth2工作方式不一样。
(7)访问令牌的范围
现在,如果访问令牌有一个受众概念(不透明令牌可能不是这样),那么RP可能需要唯一的访问令牌来访问UserInfo端点和访问资源服务器。如果是这种情况,那么可以使用相同的授权代码对令牌端点进行第二次调用,请求资源服务器的受众提供第二个访问令牌——假设OP已配置为允许这样的访问。另一个潜在的方法是利用一个作用域的访问令牌,支持多个观众——JWT允许这个——但是,OP必须支持和有潜在的安全问题,演员的数量可以做一些有趣的事情和你的身份令牌增加(因此,增加风险)。
接下来,如果RP需要额外的要求,它可以联系OP的端点用户信息获取如前所述,步骤(H) & (I)。有趣的是,RP的 ID Token ,它可以包含任何声称,可能是用户信息返回的端点。但是,OP供应商倾向于对这个特性的灵活性施加一些限制。
(8)呼叫资源服务器
接下来,RP可以访问资源的资源服务器(让我们称之为一个API在一个API提供者)通过调用API的访问令牌授权头我们以前探索——一步(J)。在理解OAuth2帖子,假设访问令牌是一个JWT令牌;JWT规范定义了如何在资源服务器(API提供者)上验证访问令牌。如果Access令牌是不透明的令牌,则资源服务器必须使用规范之外定义的机制(可能依赖于实现)与OP通信。2015年10月,发布了OAuth 2.0 Token Introspection (RFC 7662),它“定义了一种方法,让受保护的资源可以查询OAuth 2.0授权服务器,以确定OAuth 2.0令牌的活动状态,并确定有关该令牌的元信息。”基本上,它定义了一个授权服务器端点,该端点可以验证一个令牌并检索有关令牌的信息(令牌内省端点)。OIDC UserInfo端点和这个新端点之间有一些重叠,但是OAuth2令牌内省端点提供了验证不透明访问令牌的能力(尽管这不是它的主要目的)。但是访问令牌被验证了,这个步骤必须在请求处理可以在资源服务器(API提供者)-步骤(K)上进行之前完成。
最后,资源服务器可以将收到的访问令牌传递到用户信息端点获取ID标记与相关(允许)申请最终用户——步骤(L) & (M)。处理才能进行API请求和响应可以回到RP(作为API的消费者在这种情况下)。
下面的序列图中描述了我们刚刚走过的相同场景。