【问题标题】:JWT Token auth using python requests for DockerHub使用 Python 请求对 DockerHub 进行 JWT 令牌身份验证
【发布时间】:2019-08-07 19:29:19
【问题描述】:

我发现编辑 DockerHub 存储库的full_description 可以通过JavaScript API 完成,并且认为这是学习python 的requests 包的有趣借口。 JavaScript API 绝对有效,例如使用this simple docker image。

JS API 基本上是这样的

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

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

我所做的唯一“发现”:

  • 如果你添加debug logging stuff,就会有一个301。但这与javascript端的URL相同,所以没关系?

    send: b'{"full_description": "TEST"}'
    reply: 'HTTP/1.1 301 MOVED PERMANENTLY\r\n'
    
  • 通过在requests 中执行POST 收到的令牌与Getting a Bearer Token section here 中描述的GET 到auth.docker.io 相同。 值得注意的是,我没有指定密码(只是curl -X GET ...)。这不是真的。它们是不同的,我不知道我怎么认为它们是一样的。

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

代码:

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), "    "))

【问题讨论】:

  • 你能检查token的类型吗?我不确定我是否记错了,但在 python 中,有时东西会转换为字节串,突然之间它就不再起作用了。
  • 嗯,这是个好主意,我没有考虑过。 type(token) 是 str,但我会再深入一点。可能有一些旋钮我可以打开 requests 或者 urllib3 实际解码传输的响应。
  • 您能否确认您获得的令牌是实际的 JWT?您发布的 Getting a bearer token 链接似乎告诉您需要对回复进行编码以获得功能 JWT,但我不确定不知道请求的回复是什么。
  • 已编辑,我不知道为什么我认为它们是相同的……它们不是。 Can you also confirm that the token you get is an actual JWT?我不知道,但我不敢发布来自提供我的用户名/密码的回复;)我正在玩jwt module,我想我需要像你说的那样编码或解码.我希望我能帮助你帮助我,但我不知道我不知道什么 x0 我很感谢你提供建议,我会继续努力:)
  • 请您澄清问题。我不明白您认为 PATCH 请求/响应的行为方式有什么意外。您提到“尽管没有变化,但来自 PATCH 的 200 响应”,但对我来说,这是意料之中的。如果我多次发送相同的 PATCH 请求,我希望每次都能收到200 OK。

标签: python-3.x python-requests dockerhub


【解决方案1】:

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

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

正如预期的那样,PATCH 然后以更新的描述而不是旧的描述作为响应。呜呜!

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

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

【讨论】:

    【解决方案2】:

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

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

    一旦使用登录响应的 cookie 更新会话标头

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

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

    对不起,没有足够的权限来发表评论,但我认为这已经足够相关了。

    【讨论】:

    • 太棒了,感谢分享(欢迎来到 SO)! :)
    • 感谢您让我发表评论!
    猜你喜欢
    • 1970-01-01
    • 2020-03-25
    • 2018-08-29
    • 1970-01-01
    • 2016-12-17
    • 2020-09-12
    • 1970-01-01
    • 2017-02-04
    • 2023-03-10
    相关资源
    最近更新 更多