文档

19. 基于令牌的身份验证

OAuth 2 用于基于令牌的身份验证。您可以管理 OAuth 令牌以及应用程序,应用程序是 API 客户端的服务器端表示,用于生成令牌。通过将 OAuth 令牌作为 HTTP 身份验证标头的一部分,您可以进行身份验证并调整限制性权限的程度,除了基本 RBAC 权限外。有关 OAuth 2 规范的更多详细信息,请参阅 RFC 6749

有关使用 manage 实用程序创建令牌的详细信息,请参阅 令牌和会话管理 部分。

19.1. 管理 OAuth 2 应用程序和令牌

应用程序和令牌可以作为顶级资源在 /api/<version>/applications/api/<version>/tokens 中进行管理。这些资源也可以通过用户分别在 /api/<version>/users/N/<resource> 中访问。通过对 api/<version>/applications/api/<version>/users/N/applications 执行 POST 操作,可以创建应用程序。

每个 OAuth 2 应用程序代表服务器端上的特定 API 客户端。为了使 API 客户端能够通过应用程序令牌使用 API,它必须首先拥有一个应用程序并颁发访问令牌。可以通过其主键访问各个应用程序:/api/<version>/applications/<pk>/。这是一个典型的应用程序

    {
    "id": 1,
    "type": "o_auth2_application",
    "url": "/api/v2/applications/2/",
    "related": {
        "tokens": "/api/v2/applications/2/tokens/"
    },
    "summary_fields": {
        "organization": {
            "id": 1,
            "name": "Default",
            "description": ""
        },
        "user_capabilities": {
            "edit": true,
            "delete": true
        },
        "tokens": {
            "count": 0,
            "results": []
        }
    },
    "created": "2018-07-02T21:16:45.824400Z",
    "modified": "2018-07-02T21:16:45.824514Z",
    "name": "My Application",
    "description": "",
    "client_id": "Ecmc6RjjhKUOWJzDYEP8TZ35P3dvsKt0AKdIjgHV",
    "client_secret": "7Ft7ym8MpE54yWGUNvxxg6KqGwPFsyhYn9QQfYHlgBxai74Qp1GE4zsvJduOfSFkTfWFnPzYpxqcRsy1KacD0HH0vOAQUDJDCidByMiUIH4YQKtGFM1zE1dACYbpN44E",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false,
    "organization": 1
}

如上例所示,name 是应用程序的人类可读标识符。其余字段,例如 client_idredirect_uris,主要用于 OAuth2 授权,将在后面的 使用 OAuth 2 令牌系统用于个人访问令牌 (PAT) 中介绍。

在创建过程中将生成 client_idclient_secret 字段的值,它们是不可编辑的应用程序标识符,而 organizationauthorization_grant_type 是创建时必需的,并且成为不可编辑的。

19.1.1. 应用程序的访问规则

应用程序的访问规则如下

  • 系统管理员可以查看和操作系统中的所有应用程序

  • 组织管理员可以查看和操作属于组织成员的所有应用程序

  • 其他用户只能查看、更新和删除自己的应用程序,但不能创建任何新应用程序

另一方面,令牌是用于实际验证传入请求并掩盖基础用户权限的资源。有两种方法可以创建令牌

  • /api/v2/tokens/ 端点执行 POST 操作,其中包含 applicationscope 字段,以指向相关应用程序并指定令牌范围

  • /api/v2/applications/<pk>/tokens/ 端点执行 POST 操作,其中包含 scope 字段(父应用程序将自动链接)

可以通过其主键访问各个令牌:/api/<version>/tokens/<pk>/。这是一个典型的令牌示例

{
    "id": 4,
    "type": "o_auth2_access_token",
    "url": "/api/v2/tokens/4/",
    "related": {
        "user": "/api/v2/users/1/",
        "application": "/api/v2/applications/1/",
        "activity_stream": "/api/v2/tokens/4/activity_stream/"
},
    "summary_fields": {
        "application": {
            "id": 1,
            "name": "Default application for root",
            "client_id": "mcU5J5uGQcEQMgAZyr5JUnM3BqBJpgbgL9fLOVch"
        },
        "user": {
            "id": 1,
            "username": "root",
            "first_name": "",
            "last_name": ""
        }
    },
    "created": "2018-02-23T14:39:32.618932Z",
    "modified": "2018-02-23T14:39:32.643626Z",
    "description": "App Token Test",
    "user": 1,
    "token": "*************",
    "refresh_token": "*************",
    "application": 1,
    "expires": "2018-02-24T00:39:32.618279Z",
    "scope": "read"
},

对于 OAuth 2 令牌,唯一完全可编辑的字段是 scopedescription。在更新时,application 字段不可编辑,所有其他字段完全不可编辑,并且在创建期间自动填充,如下所示

  • user 字段对应于创建令牌的用户,在本例中,也是创建令牌的用户

  • expires 是根据 Tower 配置设置 OAUTH2_PROVIDER 生成的

  • tokenrefresh_token 自动生成,以确保它们是不冲突的随机字符串

应用程序令牌和个人访问令牌都显示在 /api/v2/tokens/ 端点。个人访问令牌中的 application 字段始终为 null。这是区分两种类型令牌的好方法。

19.1.2. 令牌的访问规则

令牌的访问规则如下

  • 如果用户能够查看相关应用程序,则可以创建令牌;还可以为自己创建个人令牌

  • 系统管理员能够查看和操作系统中的每个令牌

  • 组织管理员能够查看和操作属于组织成员的所有令牌

  • 系统审计员可以查看所有令牌和应用程序

  • 其他普通用户只能查看和操作自己的令牌

注意

用户只能在创建时查看令牌或刷新令牌值。

19.2. 使用 OAuth 2 令牌系统用于个人访问令牌 (PAT)

获取 OAuth 2 令牌最简单、最常用的方法是在 /api/v2/users/<userid>/personal_tokens/ 端点创建个人访问令牌,如下面的示例所示

curl -XPOST -k -H "Content-type: application/json" -d '{"description":"Personal Tower CLI token", "application":null, "scope":"write"}' https://<USERNAME>:<PASSWORD>@<TOWER_SERVER>/api/v2/users/<USER_ID>/personal_tokens/ | python -m json.tool

如果已安装,您也可以将 JSON 输出通过管道传递到 jq

以下是如何使用个人令牌通过 curl 访问 API 端点的示例

curl -k -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -X POST  -d '{}' https://tower/api/v2/job_templates/5/launch/

在 Ansible Tower 中,OAuth 2 系统建立在 Django Oauth 工具包 之上,该工具包提供了用于授权、撤销和刷新令牌的专用端点。这些端点可以在 /api/v2/users/<USER_ID>/personal_tokens/ 端点下找到,该端点还提供了一些典型用法示例。这些特殊的 OAuth 2 端点只支持使用 x-www-form-urlencoded **Content-type**,因此所有 api/o/* 端点都不接受 application/json

注意

您也可以通过为应用程序类型指定 null,使用 /api/o/token 端点请求令牌。

或者,您可以 添加令牌 用于通过 Tower 用户界面访问用户,以及配置访问令牌及其关联的刷新令牌(如果适用)的过期时间。

_images/configure-tower-system-misc-sys-token-expire.png

19.2.1. 令牌范围掩盖 RBAC 系统

OAuth 2 令牌的范围是包含有效范围关键字“read”和“write”的以空格分隔的字符串。这些关键字是可配置的,用于指定已认证的 API 客户端的权限级别。读取和写入范围在 Ansible Tower 的基于角色的访问控制 (RBAC) 权限系统上提供了一个掩码层。具体来说,“write”范围授予已认证用户 RBAC 系统提供的全部权限,而“read”范围只授予已认证用户 RBAC 系统提供的只读权限。请注意,“write”也意味着“read”。

例如,如果您对作业模板具有管理权限,则可以通过会话或基本身份验证进行身份验证,可以查看、修改、启动和删除作业模板。相反,如果您使用 OAuth 2 令牌进行身份验证,并且相关令牌范围是“read”,则即使您是管理员,您也只可以查看,但不能操作或启动作业模板。如果令牌范围是“write”或“read write”,您可以充分利用作业模板作为其管理员。

要获取和使用令牌,首先创建一个应用程序令牌

  1. 使用 authorization_grant_type 设置为 password 创建应用程序。将以下内容通过 HTTP POST 发送到 /api/v2/applications/ 端点(提供您自己的组织 ID)

{
    "name": "Admin Internal Application",
    "description": "For use by secure services & clients. ",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false,
    "organization": <organization-id>
}
  1. 创建令牌并将内容通过 POST 发送到 /api/v2/tokens/ 端点

{
    "description": "My Access Token",
    "application": <application-id>,
    "scope": "write"
}

这将返回一个 <&token-value>,您可以使用它来进行未来请求的身份验证(此值不会再次显示)。

  1. 使用令牌访问资源。以下示例使用 curl

curl -H "Authorization: Bearer <token-value>" -H "Content-Type: application/json" -X GET https://<tower>/api/v2/users/

如果您尚未设置 CA 并且使用 SSL,则可能需要 -k 标志。

要撤销令牌,您可以使用该令牌的 ID 在该令牌的详细信息页面上执行 DELETE 操作。例如

curl -ku <user>:<password> -X DELETE https://<tower>/api/v2/tokens/<pk>/

同样,使用令牌

curl -H "Authorization: Bearer <token-value>" -X DELETE https://<tower>/api/v2/tokens/<pk>/ -k

19.3. 应用程序功能

此页面列出了用于授权、令牌刷新和撤销的 OAuth 2 实用程序端点。 /api/o/ 端点不适合在浏览器中使用,不支持 HTTP GET。此处规定的端点严格遵循 OAuth 2 的 RFC 规范,因此请使用该规范作为详细参考。以下是 Tower 中这些端点典型用法的示例,特别是在使用各种授权类型创建应用程序时

  • 授权码

  • 密码

注意

您可以使用 Tower 用户界面执行此处描述的任何应用程序功能。有关更多详细信息,请参阅Ansible Tower 用户指南应用程序 部分。

19.3.1. 使用 authorization code 授权类型的应用程序

当需要直接向外部应用程序或服务颁发访问令牌时,应使用应用程序 authorization code 授权类型。

注意

您只能在使用应用程序时使用 authorization code 类型获取访问令牌。在将外部 Web 应用程序与 Ansible Tower 集成时,该 Web 应用程序可能需要代表该其他 Web 应用程序中的用户创建 OAuth2 令牌。在 Tower 中使用 authorization code 授权类型创建应用程序是首选方法,因为

  • 这允许外部应用程序使用用户的凭据从 Tower 获取令牌。

  • 为特定应用程序颁发的隔离令牌使这些令牌易于管理(例如,撤销与该应用程序关联的所有令牌,而无需撤销系统中的所有令牌)。

要使用 authorization-code 授权类型创建名为AuthCodeApp 的应用程序,请对 /api/v2/applications/ 端点执行 POST 操作

{
    "name": "AuthCodeApp",
    "user": 1,
    "client_type": "confidential",
    "redirect_uris": "http://<tower>/api/v2",
    "authorization_grant_type": "authorization-code",
    "skip_authorization": false
}


.. _`Django-oauth-toolkit simple test application`: http://django-oauth-toolkit.herokuapp.com/consumer/

当您从客户端应用程序使用 response_typeclient_idredirect_urisscopeauthorize 端点发出 **GET** 请求时发生的流程

  1. Tower 将使用授权码和状态响应应用程序中指定的 redirect_uri

  2. 然后,客户端应用程序将使用 codeclient_idclient_secretgrant_typeredirect_uri 对 Tower 上的 api/o/token/ 端点执行 **POST** 操作。

  3. Tower 将使用 access_tokentoken_typerefresh_tokenexpires_in 响应。

请参阅 Django 的测试您的授权服务器 工具包以测试此流程。

您可以在“配置 Tower - **系统**”设置中指定授权码的有效秒数

_images/configure-tower-system-misc-sys-authcode-expire.png

在此持续时间后请求访问令牌将失败。持续时间默认为 600 秒(10 分钟),基于 RFC6749 建议。

使用授权码授权类型设置与 Ansible Tower 的应用程序集成的最佳方法是将这些跨站点请求的来源列入白名单。更一般地说,您需要将您要与 Tower 集成的服务或应用程序列入白名单,您希望为其提供访问令牌。为此,请让您的管理员将此白名单添加到其本地的 Tower 设置中

CORS_ORIGIN_REGEX_WHITELIST = [
    r"http://django-oauth-toolkit.herokuapp.com*",
    r"http://www.example.com*"
]

其中 http://django-oauth-toolkit.herokuapp.comhttp://www.example.com 是需要令牌来访问 Tower 的应用程序。

19.3.2. 使用 password 授权类型的应用程序

password 授权类型或 Resource owner password-based 授权类型非常适合那些对 Web 应用程序具有本机访问权限的用户,并且应该在客户端是资源所有者时使用。以下假设一个名为“默认应用程序”的应用程序,其授权类型为 password

{
    "id": 6,
    "type": "application",
    ...
    "name": "Default Application",
    "user": 1,
    "client_id": "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l",
    "client_secret": "fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false
}

password 授权类型不需要登录,因此您可以简单地使用 curl 通过 /api/v2/tokens/ 端点获取个人访问令牌

curl -k --user <user>:<password> -H "Content-type: application/json" \
-X POST \
--data '{
    "description": "Token for Nagios Monitoring app",
    "application": 1,
    "scope": "write"
}' \
https://<tower>/api/v2/tokens/

注意

特殊的 OAuth 2 端点只支持使用 x-www-form-urlencoded **Content-type**,因此所有 api/o/* 端点都不接受 application/json

成功后,将以 JSON 格式显示响应,其中包含访问令牌、刷新令牌和其他信息

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Tue, 05 Dec 2017 16:48:09 GMT
Content-Type: application/json
Content-Length: 163
Connection: keep-alive
Content-Language: en
Vary: Accept-Language, Cookie
Pragma: no-cache
Cache-Control: no-store
Strict-Transport-Security: max-age=15768000

{"access_token": "9epHOqHhnXUcgYK8QanOmUQPSgX92g", "token_type": "Bearer", "expires_in": 315360000000, "refresh_token": "jMRX6QvzOTf046KHee3TU5mT3nyXsz", "scope": "read"}

19.4. 应用程序令牌功能

本节介绍与令牌相关的刷新和撤销功能。以下所有内容(在 /api/o/ 端点刷新和撤销令牌)目前只能使用应用程序令牌完成。

19.4.1. 刷新现有的访问令牌

以下示例显示了具有刷新令牌的现有访问令牌

{
    "id": 35,
    "type": "access_token",
    ...
    "user": 1,
    "token": "omMFLk7UKpB36WN2Qma9H3gbwEBSOc",
    "refresh_token": "AL0NK9TTpv0qp54dGbC4VUZtsZ9r8z",
    "application": 6,
    "expires": "2017-12-06T03:46:17.087022Z",
    "scope": "read write"
}

/api/o/token/ 端点用于刷新访问令牌

curl -X POST \
    -d "grant_type=refresh_token&refresh_token=AL0NK9TTpv0qp54dGbC4VUZtsZ9r8z" \
    -u "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l:fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo" \
    http://<tower>/api/o/token/ -i

在上面的 POST 请求中,refresh_token 由上面访问令牌的 refresh_token 字段提供。身份验证信息的格式为 <client_id>:<client_secret>,其中 client_idclient_secret 是访问令牌的底层相关应用程序的相应字段。

注意

特殊的 OAuth 2 端点只支持使用 x-www-form-urlencoded **Content-type**,因此所有 api/o/* 端点都不接受 application/json

成功后,将以 JSON 格式显示响应,其中包含新的(已刷新的)访问令牌,其范围信息与以前相同

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Tue, 05 Dec 2017 17:54:06 GMT
Content-Type: application/json
Content-Length: 169
Connection: keep-alive
Content-Language: en
Vary: Accept-Language, Cookie
Pragma: no-cache
Cache-Control: no-store
Strict-Transport-Security: max-age=15768000

{"access_token": "NDInWxGJI4iZgqpsreujjbvzCfJqgR", "token_type": "Bearer", "expires_in": 315360000000, "refresh_token": "DqOrmz8bx3srlHkZNKmDpqA86bnQkT", "scope": "read write"}

本质上,刷新操作会通过删除原始令牌并立即创建具有相同范围和相关应用程序的新令牌来替换现有令牌。请在 /api/v2/tokens/ 端点中验证新令牌是否存在且旧令牌已删除。

19.4.2. 撤销访问令牌

类似地,您可以使用 /api/o/revoke-token/ 端点撤销访问令牌。

通过这种方法撤销访问令牌与删除令牌资源对象相同,但它允许您通过提供令牌值和关联的 client_id(如果应用程序是 confidential,则还包括 client_secret)来删除令牌。例如

curl -X POST -d "token=rQONsve372fQwuc2pn76k3IHDCYpi7" \
-u "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l:fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo" \
http://<tower>/api/o/revoke_token/ -i

注意

特殊的 OAuth 2 端点只支持使用 x-www-form-urlencoded **Content-type**,因此所有 api/o/* 端点都不接受 application/json

注意

默认情况下,**允许外部用户创建 Oauth2 令牌**(API 中的 ALLOW_OAUTH2_FOR_EXTERNAL_USERS)设置已禁用。外部用户是指使用 LDAP 等服务或任何其他 SSO 服务在外部进行身份验证的用户。此设置可确保外部用户无法创建自己的令牌。如果您先启用然后禁用它,在此期间外部用户创建的任何令牌仍然存在,并且不会自动撤销。

或者,您可以使用 manage 实用程序,revoke_oauth2_tokens,如 令牌和会话管理 部分所述,撤销令牌。

此设置可以在 Ansible Tower 用户界面中的系统级别配置。

_images/configure-tower-system-oauth2-tokens-toggle.png

成功后,将显示 200 OK 的响应。通过检查令牌是否出现在 /api/v2/tokens/ 端点中来验证删除操作。