moyazheng 2011-04-07
4. 获得终端用户授权
在客户端能够访问一个受保护资源之前,它必须首先从终端用户那里获取授权。为了获得终端用户授权,客户端需要将终端用户引导到终端用户授权endpoint。一旦获得授权,终端用户的访问许可会被表示成一个授权码,客户端能够使用它去获取一个访问令牌。
在终端用户授权endpoint上,终端用户首先在授权服务器上完成身份验证,然后允许或者拒绝当前访问请求。授权服务器验证用户的方式(例如,用户名和密码登录,OpenID,会话cookie)和授权服务器获取终端用户授权的方式,以及是否使用诸如TSL之类的安全通道,不在本规范的规定范围之内。然而,授权服务器必须要首先验证终端用户的身份。
终端用户授权endpoint的位置能够在服务器文档中找到。终端用户授权endpoint的URI可以按照[RFC3986]第3节的定义包含一个查询参数部分,它们在添加其它参数时必须被保留。
既然对于终端用户授权endpoint的请求会导致用户身份验证和敏感信息的传输,授权服务器应该要求在向终端用户授权endpoint发送请求的时候使用诸如TLS之类的传输层安全机制。
4.1 授权请求
为了将终端用户的user-agent引导到授权服务器,客户端将下列参数添加到终端用户授权endpoint URI的查询参数部分,并使用如[W3C.REC-html401-19991224]所定义的“application/x-www-form-urlencoded”格式构建起一个请求URI,如下定义:
response_type
必需参数。请求的响应中:一个访问令牌、一个授权码,或两者都有。请求访问令牌参数值必须设为“token”,请求授权码参数值必须设为“code”,或者使用参数值为“code_and_token”同时请求两者。授权服务器可能拒绝提供这些响应类型中的一种或多种。
client_id
必需参数。如第3节所述的客户端标识符。
redirect_uri
必需参数,除非通过其它方式在客户端和授权服务器之间已经确定了一个重定向URI。这是当终端用户的授权步骤完成时授权服务器将要把user-agent重定向到的一个绝对URI。授权服务器应该要求客户端预先注册它们的重定向URI。
scope
可选参数。访问请求的作用域,以空格隔开的字符串列表来表示。“scope”参数的值由授权服务器定义。如果这个值包含多个空格隔开的字符串,那么它们的顺序不分先后,而且每个字符串都为请求的作用域增加一个新的访问范围。
state
可选参数。被客户端用来在请求和回调之间维护状态的值,对授权服务器来说是不透明的。授权服务器在将user-agent重定向回客户端时传回这个值。
客户端通过user-agent使用HTTP重定向响应,或者其它可用的方式,将终端用户引导到构建好的URI上。对于终端用户授权endpoint,授权服务器必须支持HTTP的“GET”方法,也可以支持使用“POST”方法。
例如,客户端引导终端用户的user-agent使用传输层安全机制发送下列HTTP请求(换行符只用于显示目的):
GET /authorize?response_type=code&client_id=s6BhdRkqt3&
redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
如果客户端已经在授权服务器上预先注册了一个重定向URI,授权服务器必须保证收到的重定向URI与当前客户端标识符所对应的注册URI相匹配。授权服务器不应该将user-agent重定向到没有注册过的或不信任的URI,以避免endpoint被用作一个公开的转向器。如果没有可用的有效重定向URI,授权服务器应该将发生的错误报告给用户[[提供如何执行匹配操作的建议]]。
没有值的参数必须被当做它们在请求中不存在一样。授权服务器应该忽略识别不了的请求参数。
授权服务器对请求进行验证以保证所有必需参数都存在并有效。如果请求是无效的,授权服务器将使用重定向URI把user-agent重定向回客户端,并且URI后面加上适当的错误码,如4.3节所述。
授权服务器验证终端用户的身份并获得一个授权决定(通过询问用户或通过其它方式认可)。当一个决定被做出后,授权服务器将终端用户的user-agent引导到客户端提供的重定向URI,这个重定向或者使用HTTP重定向响应,或者通过终端用户user-agent的其它可用的方式。
4.2 授权响应
如果终端用户许可了访问请求,授权服务器会分发一个访问令牌,或一个授权码,或者两者都有,并且通过将下列参数添加到重定向URI将这些分发结果传递给客户端(如下所述)。
code
如果响应类型是“code”或“code_and_token”则是必需的,否则一定不能包含这个参数。表示由授权服务器产生的授权码。授权码应该在分发后迅速过期,以降低泄露风险。客户端一定不能重用同一个授权码。如果一个授权码被多次使用,授权服务器可能撤销之前基于这个授权码分发的所有令牌。授权码与客户端标识符和重定向URI相绑定。
access_token
如果响应类型是“token”或“code_and_token”则是必需的,否则一定不能包含这个参数。表示由授权服务器分发的访问令牌。
token_type
如果响应中包含一个访问令牌则是必需的。表示分发的令牌类型。令牌类型告诉客户端一个信息,即当访问一个受保护资源时访问令牌应该如何被使用,如6.1节所述。
expires_in
可选参数。如果包含访问令牌参数,则表示访问令牌生命周期的秒数。例如,“3600”表示自响应被授权服务器产生的时刻起,访问令牌将在一小时后过期。
scope
可选参数。如果包含访问令牌参数,则表示访问令牌的作用域,表示为一个空格隔开的字符串列表。“scope”参数的值由授权服务器定义。如果这个值包含多个空格隔开的字符串,那么它们的顺序不分先后,而且每个字符串都为请求的作用域增加一个新的访问范围。如果请求到的作用域不同于客户端申请的作用域,授权服务器应该传回这个参数。
state
如果“state”参数在客户端授权请求中存在,则这个参数是必需的。需要精确地设置成从客户端接收到的值。
授权服务器在重定向URI上添加参数的方式取决于客户端在授权请求中请求的响应类型,由“response_type”参数指定。
如果响应类型是“code”,授权服务器使用如[W3C.REC-html401-19991224]所定义的“application/x-www-form-urlencoded”格式添加参数到重定向URI的查询参数部分。
例如,授权服务器通过发送下列HTTP响应将终端用户的user-agent进行重定向:
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=i1WsRn1uB1
如果响应类型是“code”或“code_and_token”,授权服务器使用如[W3C.REC-html401-19991224]所定义的“application/x-www-form-urlencoded”格式添加参数到重定向URI的分段参数部分。
例如,授权服务器通过发送下列HTTP响应将终端用户的user-agent进行重定向(URI换行符只用于显示目的):
HTTP/1.1 302 Found
Location: http://example.com/rd#access_token=FJQbwq9&
token_type=example&expires_in=3600
客户端应该忽略无法识别的响应参数。从授权服务器接收到的令牌和其它参数值的大小,本规范未作定义。客户端应该避免对参数值大小做任何假设。服务器应该对它们所分发的任何参数值的期望大小做出文档说明。
4.3 错误响应
如果终端用户拒绝了访问请求,或者由于除了缺少或无效重定向URI之外的其它原因而导致请求失败,授权服务器使用如[W3C.REC-html401-19991224]所定义的“application/x-www-form-urlencoded”格式添加下列参数到重定向URI的查询参数部分以通知客户端:
error
必需参数。如4.3.1节所述的一个错误码。
error_description
可选参数。提供额外信息的一段人类可读的文字,用来帮助理解和解决发生的错误。
error_uri
可选参数。指明了一个人类可读的网页URI,带有关于错误的信息,用来为终端用户提供与错误有关的额外信息。
state
如果“state”参数在客户端授权请求中存在,则这个参数是必需的。需要精确地设置成从客户端接收到的值。
例如,授权服务器通过发送下列HTTP响应将终端用户的user-agent进行重定向:
HTTP/1.1 302 Found
Location: https://client.example.com/cb?error=access_denied
如果由于缺少或无效重定向URI而导致请求失败,授权服务器应该通知终端用户这个错误,而一定不能将终端用户的user-agent重定向到这个无效的重定向URI。
4.3.1 错误码
授权服务器在错误响应中包含下列错误码之一:
invalid_request
请求缺少某个必需参数,包含一个不支持的参数或参数值,或者格式不正确。
invalid_client
提供的客户端标识符是无效的。
unauthorized_client
客户端没有权限使用该请求的响应类型。
redirect_uri_mismatch
提供的重定向URI与预先注册的值不匹配。
access_denied
终端用户或授权服务器拒绝了请求。
unsupported_response_type
请求的响应类型不为授权服务器所支持。
invalid_scope
请求的作用域是无效的、未知的,或格式不正确的。
[[增加扩展错误码的机制]]
5. 获取访问令牌
客户端通过在授权服务器上验证并出示它的访问许可(表示成授权码、资源拥有者私有证书、断言或刷新令牌的形式)来获取一个访问令牌。
既然对于令牌endpoint的请求会导致在HTTP请求和响应中传输明文证书,授权服务器必需要求在向令牌endpoint发送请求的时候使用传输层安全机制。服务器必需支持[RFC5246]所定义的TLS 1.2,并且可能支持额外的传输层安全机制。
客户端通过向令牌endpoint发送一个HTTP POST请求来获取一个访问令牌。令牌endpoint的位置能够在服务器文档中找到。令牌endpoint URI可能包含一个查询参数部分。
客户端通过在请求中添加客户端私有证书与授权服务器进行验证,如第3节所述。当客户端标识符不重要的时候(例如匿名客户端),或当客户端标识符通过其它方式确定的时候(例如使用一个断言访问许可),授权服务器可能允许不经验证的访问令牌请求。
客户端通过在HTTP请求的entity-body中使用“application/x-www-form-urlencoded”格式包含下列参数,来构建请求:
grant_type
必需参数。在请求中所包含的访问许可类型。它的值必须是“authorization_code”、“password”、“refresh_token”、“client_credentials”或一个用来标识被授权服务器所支持的断言类型的绝对URI。
scope
可选参数。访问请求的作用域,表达为一个由空格隔开的字符串列表。“scope”参数的值由授权服务器定义。如果这个值包含多个空格隔开的字符串,那么它们的顺序不分先后,而且每个字符串都为请求的作用域增加一个新的访问范围。如果使用的访问许可已经代表了一个许可作用域(例如,授权码、断言),那么请求的作用域必须等于或少于之前许可的作用域,如果缺少这个参数就认为是等于之前的许可作用域。
另外,对于5.1节列出的某个访问许可类型,客户端必须包含合适的参数。
没有值的参数必须被当做它们在请求中不存在一样。授权服务器应该忽略识别不了的请求参数。
5.1 访问许可类型
客户端使用一个授权码、资源拥有者密码证书、客户端私有证书、刷新令牌或断言来请求一个访问许可。
5.1.1 授权码
客户端使用“authorization_code”访问许可类型和下列参数传入授权码:
code
必需参数。从授权服务器接收到的授权码。
redirect_uri
必需参数。在最初请求中使用的重定向URI。
例如,客户端通过如第3节所述的“client_secret”参数包含客户端私有证书,并使用传输层安全机制,来发送下列HTTP请求(换行符只用于显示目的):
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=s6BhdRkqt3&
client_secret=gX1fBat3bV&code=i1WsRn1uB1&
redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
授权服务器必须:
如果请求有效,授权服务器分发一个成功响应,如5.2节所述。
5.1.2 资源拥有者密码证书
客户端使用“password”访问许可类型和下列参数传入资源拥有者密码证书:[[增加对于用户名和密码的国际化考虑]]
username
必需参数。资源拥有者的用户名。
password
必需参数。资源拥有者的密码。
例如,客户端通过如第3节所述的“client_secret”参数包含客户端私有证书,并使用传输层安全机制,来发送下列HTTP请求(换行符只用于显示目的):
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&client_id=s6BhdRkqt3&
client_secret=47HDu8s&username=johndoe&password=A3ddj3w
授权服务器必须验证客户端私有证书(如果存在)和终端用户私有证书,而且如果发现有效则必须发布一个访问令牌响应,如5.2节所述。
5.1.3 客户端私有证书
客户端可以仅仅使用它的客户端私有证书来请求一个访问令牌,即使用“client_credentials”访问许可类型。当省略一个显式的访问许可时,客户端是在请求访问它所控制的受保护资源,或另一个资源拥有者之前与授权服务器约定好的受保护资源(约定方式不在本规范的规定范围之内)。
5.1.4 刷新令牌
客户端使用“refresh_token”访问许可类型和下列参数传入刷新令牌:
refresh_token
必需参数。与待刷新的访问令牌相关联的刷新令牌。
例如,客户端通过如第3节所述的“client_secret”参数包含客户端私有证书,并使用传输层安全机制,来发送下列HTTP请求(换行符只用于显示目的):
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&client_id=s6BhdRkqt3&
client_secret=8eSEIpnqmM&refresh_token=n4E9O119d
授权服务器必须验证客户端私有证书(如果存在),验证刷新令牌是否有效,以及验证资源拥有者的授权是否仍然有效。如果请求有效,授权服务器则发布一个访问令牌响应,如5.2节所述。授权服务器可以发布一个新的刷新令牌,在这种情况下,客户端必须丢弃旧的刷新令牌并且用新的访问令牌替换。
5.1.5 断言
客户端使用一个绝对URI(由授权服务器定义)作为“grant_type”参数的值指定断言格式,并添加下列参数,来传入一个断言:
assertion
必需参数。断言。
例如,客户端使用传输层安全机制来发送下列HTTP请求,且客户端验证通过断言来完成(换行符只用于显示目的):
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aoasis%3Anames%3Atc%3ASAML%3A2.0%3Aassertion&
assertion=PHNhbWxwOl[...omitted for brevity...]ZT4%3D
授权服务器必须验证客户端私有证书(如果存在)和断言,而且如果发现有效则必须发布一个访问令牌响应,如5.2节所述。授权服务器不应该分发一个刷新令牌(而是应该要求客户端使用相同的或新的断言)。
授权服务器应该分发具有有限生命周期的访问令牌,并且要求客户端使用仍然有效的同一个断言来请求新的访问令牌,从而完成对令牌的刷新。
5.2 访问令牌响应
在接收到并验证过来自客户端的一个有效且经授权的访问令牌请求之后,授权服务器分发访问令牌和可选的刷新令牌,并且通过一个200(OK)状态码在HTTP响应的entity body中添加下列参数来构造响应:
令牌响应包含下列参数:
access_token
必需参数。由授权服务器分发的访问令牌。
token_type
必需参数。分发的令牌类型。令牌类型告诉客户端一个信息,即当访问一个受保护资源时访问令牌应该如何被使用,如6.1节所述。
expires_in
可选参数。访问令牌生命周期的秒数。例如,“3600”表示自响应被授权服务器产生的时刻起,访问令牌将在一小时后过期。
refresh_token
可选参数。用来获取新的访问令牌的刷新令牌,如5.1.4节所述使用相同的终端用户访问许可。当访问许可类型是一个断言或一个客户端私有证书集合时,授权服务器不应该分发一个刷新令牌。
scope
可选参数。访问令牌的作用域,表示为一个空格隔开的字符串列表。“scope”参数的值由授权服务器定义。如果这个值包含多个空格隔开的字符串,那么它们的顺序不分先后,而且每个字符串都为请求的作用域增加一个新的访问范围。如果请求到的作用域不同于客户端申请的作用域,授权服务器应该传回这个参数。
参数包含在HTTP响应的entity body中,使用[RFC4627]定义的“application/json”媒体类型。通过在最高结构层次上添加每个参数,将它们序列化成一个JSON结构。参数名和字符串值都表示成JSON字符串。数字值表示成JSON数字。
在任何包含令牌、密钥或其它敏感信息的响应中,授权服务器必须在“Cache-Control”响应头部字段中传入一个“no-store”的值。
例如:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"access_token":"SlAV32hkKG",
"token_type":"example",
"expires_in":3600,
"refresh_token":"8xLOxBtZp8"
}
客户端应该忽略无法识别的响应参数。从授权服务器接收到的令牌和其它参数值的大小,本规范未作定义。客户端应该避免对参数值大小做任何假设。服务器应该对它们所分发的任何参数值的期望大小做出文档说明。
5.3 错误响应
如果令牌请求是无效的或未经授权的,授权服务器通过在HTTP响应的entity body中添加下列参数并使用“application/json”媒体类型来构造响应:
error
必需参数。如4.3.1节所述的一个错误码。
error_description
可选参数。提供额外信息的一段人类可读的文字,用来帮助理解和解决发生的错误。
error_uri
可选参数。指明了一个人类可读的网页URI,带有关于错误的信息,用来为终端用户提供与错误有关的额外信息。
例如:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
{
"error":"invalid_request"
}
如果客户端通过“Authorization”请求头部字段使用HTTP验证机制这种方式提供了无效的私有证书,那么授权服务器必须用HTTP 401(Unauthorized)状态码进行响应。否则,授权服务器应该用HTTP 400(Bad Request)状态码进行响应。
5.3.1 错误码
授权服务器在错误响应中传回下列错误码之一:
invalid_request
请求缺少某个必需参数,包含一个不支持的参数或参数值,参数重复,包含多个私有证书,使用了多种验证客户端的机制,或者请求格式不正确。
invalid_client
提供的客户端标识符是无效的,客户端验证失败,客户端不包含私有证书,提供了多个客户端私有证书,或使用了不支持的证书类型。
unauthorized_client
经过验证的客户端没有权限使用提供的访问许可类型。
invalid_grant
提供的访问许可是无效的、过期的或已撤销的(例如,无效的断言,过期的授权令牌,错误的终端用户密码证书,或者不匹配的授权码和重定向URI)。
unsupported_grant_type
包含的访问许可——它的类型或其它属性——不被授权服务器所支持。
invalid_scope
请求的作用域是无效的、未知的、格式不正确的,或超出了之前许可的作用域。
[[增加扩展错误码的机制]]
6. 访问受保护资源
客户端通过向资源服务器出示一个访问令牌来访问受保护资源。资源服务器必须验证访问令牌,保证它没有过期并且它的作用域覆盖了请求的资源。被资源服务器用来验证访问令牌的方式不在本规范的规定范围之内,但是它通常需要在资源服务器和授权服务器之间进行交互或配合。
客户端利用访问令牌来验证资源服务器的方式取决于由授权服务器分发的访问令牌类型。
6.1 访问令牌类型
[[增加令牌类型的解释,可能包含指定其它规范的链接]]