跳转到主要内容

Plone的令牌认证

项目描述

ftw.tokenauth

PAS插件,通过实现使用服务密钥和短寿命访问令牌的双端OAuth2流程,简化了机器之间的认证。

安装

  • ftw.tokenauth添加到您的buildout配置或作为策略包的依赖项。

[instance]
eggs +=
    ftw.tokenauth
  • 安装ftw.tokenauth的通用设置配置文件。

配置

要允许用户发布(或以其他方式管理)服务密钥,他们需要ftw.tokenauth: Manage own Service Keys权限。因此,集成包需要将此权限分配给应允许使用服务密钥的角色。

认证流程

认证流程包括四个步骤

  1. 登录的服务用户在Plone中发布服务密钥,并将私钥存储在客户端应用程序可安全访问的位置。

  2. 客户端应用程序使用私钥创建并签名JWT授权授予。

  3. 客户端应用程序将JWT授权授予与@@oauth2-token端点的短寿命访问令牌进行交换。

  4. 客户端随后使用此访问令牌来验证对受保护资源的请求。

假设客户端拥有服务密钥,则流程如下

https://github.com/4teamwork/ftw.tokenauth/raw/master/docs/authentication-flow.png

基本用法

为了为客户端设置机器之间的认证,需要执行以下步骤

1. 发布服务密钥

已通过常规方式认证到Plone并具有ftw.tokenauth: Manage own Service Keys权限的用户,可以通过@@manage-service-keys视图(个人工具菜单中的“管理服务密钥”操作)为其账户发布服务密钥。

https://github.com/4teamwork/ftw.tokenauth/raw/master/docs/manage-service-keys.png

他们需要发布一个服务密钥,该密钥将恰好一次显示以供下载,并将私钥存储在客户端可安全访问的位置。

https://github.com/4teamwork/ftw.tokenauth/raw/master/docs/issue-service-key.png

在发布密钥时,还可以定义IP范围限制

待办事项:记录密钥撤销。

2. 使用服务密钥创建和签名JWT授权授予

为了请求访问令牌,客户端应用程序随后使用私服务密钥创建和签名JWT。

JWT需要包含以下声明

名称

描述

iss

发行者 - 必须是服务密钥中的client_id

aud

受众 - 必须是服务密钥中的token_uri

sub

主题 - 必须是服务密钥中的user_id或允许冒充其他用户的现有用户的任意用户ID。

iat

声明发布的时间,指定为自1970年1月1日00:00:00 UTC以来的秒数。

exp

声明的过期时间,指定为自1970年1月1日00:00:00 UTC以来的秒数。此值在发布时间后最多1小时。

JWT然后需要使用私钥签名。唯一支持的签名算法是RS256

Python示例

import json
import jwt
import time

# Load saved key from filesystem
service_key = json.load(open('my_saved_key.json', 'rb'))

private_key = service_key['private_key'].encode('utf-8')

claim_set = {
    "iss": service_key['client_id'],
    "sub": service_key['user_id'],
    "aud": service_key['token_uri'],
    "iat": int(time.time()),
    "exp": int(time.time() + (60 * 60)),
}
grant = jwt.encode(claim_set, private_key, algorithm='RS256')

3. 令牌请求(交换JWT授予以获取访问令牌)

客户端随后使用其创建的JWT授予向token_uri发出令牌请求。

此请求必须是POST请求,Content-Type: application/x-www-form-urlencoded,并且请求体包含表单编码的参数。

需要两个参数

名称

描述

grant_type

必须始终是urn:ietf:params:oauth:grant-type:jwt-bearer

assertion

JWT授权授予

令牌端点随后将响应一个包含访问令牌的令牌响应

{
  "access_token": "<token>",
  "expires_in": 3600,
  "token_type": "Bearer"
}

响应将为 Content-Type: application/json,并包含一个JSON编码的正文。

Python示例

import requests

GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:jwt-bearer'

payload = {'grant_type': GRANT_TYPE, 'assertion': grant}
response = requests.post(service_key['token_uri'], data=payload)
token = response.json()['access_token']

待办:记录令牌请求的错误响应

4. 使用访问令牌进行身份验证

客户端可以使用访问令牌进行身份验证。令牌需要以HTTP Authorization头中的Bearer令牌的形式发送。

一旦令牌过期,客户端必须再次创建JWT授权授予,并请求新的访问令牌。

Python示例

with requests.Session() as session:
    session.headers.update({'Authorization': 'Bearer %s' % token})
    response = session.get('https://127.0.0.1:8080/Plone/')
    # ...

如果客户端使用的令牌已过期,服务器将响应错误响应

{
  "error": "invalid_token",
  "error_description": "Access token expired"
}

然后客户端应签署另一个JWT身份验证授予,请求新的令牌,并使用原始参数以及新的令牌重新发送失败的请求。

高级用法

本节涵盖了一些关于ftw.tokenauth的高级设置和功能。

IP范围限制

在颁发密钥时,可以定义IP范围限制,限制与该密钥关联的访问令牌可以使用的源IP地址。

给定密钥的IP范围限制的更改立即生效,并影响已颁发给此密钥的令牌。

IP范围可以指定为单个IP地址或使用斜杠后缀的CIDR表示法

可以以逗号分隔的形式提供多个范围。

有效IP范围指定的示例

  • 192.168.1.1

  • 192.168.0.0/16

  • 192.168.1.1, 10.0.0.0/8

来自未经授权的源IP地址的认证尝试将在服务器端进行记录,但不会以任何特定方式通知客户端 - 认证只是没有执行。

伪装

伪装允许以任意用户身份进行身份验证,而不是颁发服务密钥的用户。如果例如应用程序需要在不同用户上下文中执行操作,则这很有用。

要能够伪装成另一个用户,服务密钥用户需要具有ftw.tokenauth: Impersonate user权限。默认情况下,此权限仅授予Manager角色。请注意,使用此权限,用户可以伪装成具有更高权限的用户,因此实际上获得了系统中最有权限用户的全部权限。

要伪装成用户,在请求访问令牌时,请传递其用户ID或登录名,而不是服务密钥用户的用户ID,并在JWT令牌中使用sub声明。

使用日志

在“管理服务密钥”视图中,“Last Used”列列出了密钥最后一次用于颁发访问令牌的时间。点击此时间戳将显示密钥最近使用情况的详细日志。

默认情况下,这些日志列出了密钥在过去7天内的使用情况(使用日志保留期可以通过ZMI上的PAS插件属性进行配置)。

密钥最近一次使用记录始终保留,而其他日志条目如果已过期则会被清理(清理发生在每次颁发新访问令牌时)。

日志不显示访问令牌的认证使用情况,而是显示使用此密钥签名的JWT认证实例用于获取新访问令牌的每个实例。

变更日志

1.2.0 (2023-12-13)

  • 添加根据用户名(登录)查找备选用户的实现。[phgross]

1.1.0 (2018-07-12)

  • 允许模拟其他用户。[buchi]

1.0.1 (2018-04-16)

  • 将IP范围解析从py2-ipaddress模块切换到ipaddress模块,并修复了Unicode处理问题。[lgraf]

1.0.0 (2018-04-04)

  • 初始实现 [lgraf]

项目详情


下载文件

下载您平台对应的文件。如果您不确定选择哪个,请了解更多关于安装软件包的信息。

源代码分发

ftw.tokenauth-1.2.0.tar.gz (197.2 kB 查看哈希值)

上传时间 源代码

支持者