JWT 令牌身份验证使用 python 请求 DockerHub

JWT Token auth using python requests for DockerHub

我发现可以通过 JavaScript API, and figured this would be a fun excuse to learn the requests package for python. The JavaScript API definitely works, e.g. using this simple docker image.

编辑 DockerHub 存储库的 full_description

JS API 基本上可以

  1. Send a POST requesthttps://hub.docker.com/v2/users/login 使用用户名和密码。服务器响应 token.
  2. Send a PATCH request 到特定的 https://hub.docker.com/v2/repositories/{user or org}/{repo},确保 header 有 Authorization: JWT {token},在这种情况下 body 的 {"full_description":"...value..."} ].

令人不安的是,python 端的 PATCH 请求从服务器返回 200 响应(如果您故意设置错误的身份验证令牌,您将按预期被拒绝)。但它的响应实际上包含当前信息(不是补丁信息)。

我唯一的"discoveries":

第二个让我觉得我少了一步。就像我需要解码令牌之类的?我不知道还能做什么,尤其是 PATCH200 响应,尽管没有任何变化。

代码:

import json
from textwrap import indent
import requests


if __name__ == "__main__":
    username = "<< SET THIS VALUE >>"
    password = "<< SET THIS VALUE >>"
    repo = "<< SET THIS VALUE >>"

    base_url = "https://hub.docker.com/v2"
    login_url = f"{base_url}/users/login"
    repo_url = f"{base_url}/repositories/{username}/{repo}"

    # NOTE: if I use a `with requests.Session()`, then I'll get
    # CSRF Failed: CSRF token missing or incorrect
    # Because I think that csrftoken is only valid for login page (?)
    # Get login token and create authorization header
    print("==> Logging into DockerHub")
    tok_req = requests.post(login_url, json={"username": username, "password": password})
    token = tok_req.json()["token"]
    headers = {"Authorization": f"JWT {token}"}

    print(f"==> Sending PATCH request to {repo_url}")
    payload = {"full_description": "TEST"}
    patch_req = requests.patch(repo_url, headers=headers, json=payload)
    print(f"    Response (status code: {patch_req.status_code}):")
    print(indent(json.dumps(patch_req.json(), indent=2), "    "))

事实证明,JWT {token} 身份验证一直有效。显然,您需要在 URL 末尾添加一个 /。没有它,什么也不会发生。哈哈!

# ----------------------------------------------------V
repo_url = f"{base_url}/repositories/{username}/{repo}/"

正如预期的那样,PATCH 然后使用更新的描述而不是旧描述进行响应。太棒了!

重要说明:截至 2020 年 1 月 15 日,这对我有用,但在我的探索中,我遇到了 this dockerhub issue,这似乎表明如果您的帐户启用了 2FA,您将无法再编辑description 使用 PATCH 请求。我的帐户上没有 2FA,所以我可以(显然)。还不清楚它的未来会怎样。

相关说明:JWT 令牌一直保持不变,因此对于像我这样的网络新手,请不要共享这些 ;)

使用 requests.Session() 时与您的 CSRF 问题相关的其他信息:

在这种情况下发出请求时,Docker Hub 似乎无法识别名为 header/cookie 的 csrftoken(即将到来的 cookie 的默认名称)。 相反,当在以下请求中使用 header X-CSRFToken 时,CSRF 被识别为有效。 也许原因是 cookie-to-header token pattern.

使用登录响应的 cookie 更新 session header 后

s.headers.update({"X-CSRFToken": s.cookies.get("csrftoken")})

无需再为进一步的请求手动设置 JWT 令牌 - 令牌已作为 cookie 使用。

抱歉,没有足够的权限来发表评论,但我认为这足够相关。