【问题标题】:Using OAuth 2 to authenticate to Azure DevOps REST APIs fails with TF400813 (user not authorized)使用 OAuth 2 对 Azure DevOps REST API 进行身份验证失败并出现 TF400813(用户未授权)
【发布时间】:2021-07-15 23:19:25
【问题描述】:

我正在关注此处发布的文档 (https://docs.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/oauth?view=azure-devops)。

我在 Azure 中有一个基于 react 的 web 应用和一个基于 powershell 的函数应用。我的函数应用目前正在使用使用我的工作帐户 (AAD) 凭据创建的个人访问令牌,这是不可取的。我的目标是使用 OAuth2 授权我的函数应用代表 webapp 用户对 GIT 存储库进行代码更改。当我按照上面的说明进行操作时,我能够获取看似有效的授权代码、访问令牌和刷新令牌,我从 Azure DevOps 收到以下错误消息:

TF400813:用户 'ffffffff-ffff-ffff-ffff-ffffffffffff' 无权访问此资源。 … 401 - 哦,你没有访问权限。 该请求需要身份验证。 2021 年 4 月 21 日上午 12:04:16 (UTC) ffffffff-ffff-ffff-ffff-ffffffffffff 退出并使用其他帐户登录

我在上面的示例中隐藏了 guid,但是当我调用旧版身份 API (https://docs.microsoft.com/en-us/rest/api/azure/devops/ims/identities/read%20identities?view=azure-devops-rest-6.0) 时,用户 GUID 似乎与我为我的工作帐户找到的 GUID 匹配。 我创建了我的应用程序 (https://app.vsaex.visualstudio.com/app/register),其作用域与用于创建个人访问令牌的作用域相同。我在 dev.azure.com 个人资料中验证了我的应用程序被列为授权 OAuth 应用程序,正如在创建授权请求并收到授权代码后所预期的那样。

上面的错误信息让我很困惑。它说用户(我)无权访问资源,但也说身份验证失败。是哪个?

这与我获取授权/访问令牌的方式有关吗?我是否以某种方式使用了错误的帐户?我的范围错了吗?

问题的再现

这是我注册申请的状态:

My application state:
{
    "scopes": "vso.code_full vso.code_status vso.graph_manage vso.identity_manage vso.threads_full vso.tokens",
    "tokenUrl": "https://app.vssps.visualstudio.com/oauth2/token",
    "state": "foo",
    "authCallback": "https://myapp.azurewebsites.net/oauth-callback",
    "clientSecret": "S.S.S-S-S",
    "authUrl": "https://app.vssps.visualstudio.com/oauth2/authorize",
    "appWebsite": "https://myapp.azurewebsites.net/",
    "appSecret": "S",
    "appId": "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"
}

步骤 1. 授权应用程序。

I invoke the following auth URI from an in-private browser.
I authenticate my work account, and authorize the application for the requested scopes.
I can verify the app is an authorized oauth app in my dev.azure.com profile.

https://app.vssps.visualstudio.com/oauth2/authorize?client_id=FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF&response_type=Assertion&state=foo&scope=vso.code_full%20vso.code_status%20vso.graph_manage%20vso.identity_manage%20vso.threads_full%20vso.tokens&redirect_uri=https://myapp.azurewebsites.net/oauth-callback

I receive an authcode, "A.A.A-A-A-A" (shown decoded/obfuscated below):
{
    "typ": "JWT",
    "alg": "RS256",
    "x5t": "....."
}
{
    "cid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
    "csi": "ffffffff-ffff-ffff-ffff-ffffffffffff",
    "nameid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
    "iss": "app.vstoken.visualstudio.com",
    "aud": "app.vstoken.visualstudio.com",
    "nbf": 1618438026,
    "exp": 1776204426
}

步骤 2. 从我的 powershell 函数应用中请求访问令牌和刷新令牌:

I make a rest api call to the token endpoint:
  "Uri": "https://app.vssps.visualstudio.com/oauth2/token"
  "Method": "POST"
  "ContentType": "application/x-www-form-urlencoded"
  "Body": "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=S.S.S-S-S&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=A.A.A-A-A-A&redirect_uri=https://myapp.azurewebsites.net/oauth-callback"

…and I get the following JSON response:
Token Response:
{
    "access_token": "X.X.X-X-X-X-X-X-X",
    "token_type": "jwt-bearer"
    "expires_in": 3599,
    "refresh_token": "R.R.R-R-R-R",
    "scope": "vso.code_full vso.code_status vso.graph_manage vso.identity_manage vso.threads_full vso.tokens vso.authorization_grant"
}

Yielding the following JWT for the access token:
{
    "typ": "JWT",
    "alg": "RS256",
    "x5t": "....."
}
{
    "nameid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
    "scp": "vso.code_full vso.code_status vso.graph_manage vso.identity_manage vso.threads_full vso.tokens",
    "aui": "ffffffff-ffff-ffff-ffff-ffffffffffff",
    "appid": "ffffffff-ffff-ffff-ffff-ffffffffffff",
    "iss": "app.vstoken.visualstudio.com",
    "aud": "app.vstoken.visualstudio.com",
    "nbf": 1618963456,
    "exp": 1618967056
}

第 3 步。调用 DevOps REST API。

In this case, I am requesting a list of respositories in my org/project:
  "Uri": "https://dev.azure.com/myorg/myproj/_apis/git/repositories?api-version=6.0"
  "Method": "GET"
  "Headers": {"Authorization": "Bearer X.X.X-X-X-X-X-X-X"}

This is where things go wrong.  DevOps returns a 401 error indicating that my account is not authorized.
  TF400813: The user 'ffffffff-ffff-ffff-ffff-ffffffffffff' is not authorized to access this resource.

如果我在第 3 步中创建了完全相同的 http GET,但我将 PAT 替换为与注册应用程序相同的范围,则调用成功。 PAT 似乎是使用第 1 步中授权的完全相同的配置文件/帐户创建的。

【问题讨论】:

  • 这里有一些类似问题的ticket(case1case2)可以参考。

标签: azure-devops oauth-2.0 azure-devops-rest-api


【解决方案1】:

当组织管理员在设置中禁用 OAuth 时,可以观察到此行为。组织的任何成员都可以查看相关选项,例如https://dev.azure.com/contoso/_settings/organizationPolicy

遗憾的是,据我所知,对于应用程序或用户来说,没有更好的指示。

您的应用仍然可以请求用户授权,所有 OAuth 操作都成功,返回看似有效的访问令牌,但随后它根本不起作用并从所有 API 返回 401,即使 PAT 具有相同的范围(s ) 工作正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-09
    • 2021-08-11
    • 2021-07-17
    • 2019-07-09
    • 2014-02-27
    相关资源
    最近更新 更多