JWT 插件

JWT 插件已弃用,并将于 2018 年 4 月 17 日停止使用

Travis-CI 与第三方服务(如 Sauce Labs)之间的集成依赖于 加密变量,这对于受信任的分支和提交者来说效果很好。出于安全原因,加密变量不会暴露给不受信任的 Pull Request,因此 Pull Request 的构建无法访问第三方集成。

JWT 插件用时间受限的身份验证令牌替换加密变量,该令牌会暴露给 Pull Request 而不产生安全后果。

为了使此功能正常工作,需要在 .travis.yml 文件中启用 JWT 插件,并且第三方需要与 JWT 服务集成并允许基于令牌的身份验证。

JWT Travis Flow Diagram

.travis.yml #

将加密密钥添加到 .travis.yml 文件的 jwt 部分。这可以通过手动操作或使用 travis encrypt 命令完成。

Travis 加密

travis encrypt --add addons.jwt SAUCE_ACCESS_KEY=your-access-key

手动操作

addons:
  jwt:
     secure: <SAUCE_ACCESS_KEY ENCRYPTED>

这也可以支持多种服务

travis encrypt --add addons.jwt SAUCE_ACCESS_KEY=your-access-key THIRDPARTY_SHARED_SECRET=another-key

手动操作

addons:
  jwt:
    - secure: <SAUCE_ACCESS_KEY ENCRYPTED>
    - secure: <THIRDPARTY_SHARED_SECRET ENCRYPTED>

使用加密密钥 #

原始变量名称在 Travis CI 构建中可用,作为包含 JWT 令牌而不是原始值的 environment 变量。

例如,使用先前的配置 SAUCE_ACCESS_KEYTHIRDPARTY_SHARED_SECRET 将作为 environment 变量可用。

此插件有多安全? #

JWT 令牌仅有效 90 分钟。它以一种安全的方式签名,让您可以在无需担心泄露的情况下安全地传输您的秘密信息。

故障排除 #

  1. 检查第三方服务是否 受支持
  2. 联系第三方支持并向他们提供加密令牌(在测试脚本中回显密钥),并链接到 Travis 作业。

第三方服务集成 #

第三方服务需要在服务器端实现新的身份验证方法,以便识别和验证 JWT 令牌。

JWT 库 #

JWT.io 提供了 支持的语言 的完整列表以及有关所有内容如何工作的文档。

有效载荷 #

用于生成 JWT 令牌的有效载荷示例。

{
  "iss": "Travis CI, GmbH",
  "slug": "saucelabs-sample-test-frameworks/Java-TestNG-Selenium",
  "pull-request": 15,
  "exp": 1470111801,
  "iat": 1470106401
}

其中

  • slug 将是 travis 链接的 slug
  • pull-request 将为空 ("") 或 Pull Request 的整数
  • exp 将是令牌过期时间(现在 + 5400 秒,即 90 分钟)
  • iat 是颁发时间(现在)

第三方服务提供商代码示例 #

一个说明如何向第三方服务添加 JWT 令牌身份验证的代码示例。

Python #

在此示例中,我们假设 RESTful API 的身份验证凭据(使用 environment 变量,例如 SERVICE_USERNAME + SERVICE_ACCESS_KEY)将作为 HTTP BASIC AUTH 标头发送。

Authorization: Basic am9obmRvZTpleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpJVXpJMU5pSjkuZXlKcGMzTWlPaUow\nY21GMmFYTXRZMmt1YjNKbklpd2ljMngxWnlJNkluUnlZWFpwY3kxamFTOTBjbUYyYVhNdFkya2lM\nQ0p3ZFd4c0xYSmxjWFZsYzNRaU9pSWlMQ0psZUhBaU9qVTBNREFzSW1saGRDSTZNSDAuc29RSmdI\nUjZjR05yOUxqX042eUwyTms1U1F1Zy1oWEdVUGVuSnkxUVRWYw==

HTTP BASIC AUTH 标头的有效载荷是 base64 编码的,它将解码为如下字符串。

johndoe:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ0cmF2aXMtY2kub3JnIiwic2x1ZyI6InRyYXZpcy1jaS90cmF2aXMtY2kiLCJwdWxsLXJlcXVlc3QiOiIiLCJleHAiOjU0MDAsImlhdCI6MH0.soQJgHR6cGNr9Lj_N6yL2Nk5SQug-hXGUPenJy1QTVc

以冒号分隔的字符串包含冒号之前的用户名和冒号之后的 JWT 令牌。用户名用于从用户数据库中检索用户对象。下面是一个针对用户对象和令牌执行以验证它们进行身份验证的函数。请注意,代码有意与 access_key 包含的值无关。JWT 令牌或访问密钥传递到函数中都没有关系。但是,服务提供商必须将 JWT 身份验证尝试添加到现有的身份验证机制中。

import jwt

def authenticate(user, access_key):
    """
    user: db object representing user retrieved based on username from HTTP BASIC AUTH
    access_key: access key or JWT token signed using access key (shared secret)
    returns True when authentication validation passed, otherwise False
    """
    # primary auth method
    if user['access_key'] == access_key:
        return True

    # secondary auth attempt using JWT method
    try:
        return bool(jwt.decode(access_key, user['access_key']))
    except (jwt.DecodeError, jwt.ExpiredSignature):
        return False

与 JWT 插件集成的第三方服务列表 #

Sauce Labs #

将您的 SAUCE_USERNAME 添加为常规 environment 变量,并将您的 SAUCE_ACCESS_KEY 添加为 JWT 令牌(有关更多详细信息,请参阅 sauce-connect

env:
  - SAUCE_USERNAME=example_username
addons:
  jwt:
    secure: <SAUCE_ACCESS_KEY ENCRYPTED>