如何在使用 Azure OAuth 客户端凭据流时向访问令牌添加可选声明

6
在我的场景中,有一个Azure应用程序注册(client_app),具有凭据。该应用程序用于请求oauth2访问令牌。第二个应用程序注册(main_app)是提供应用程序角色和更多内容的范围。
我的目标是在使用Azure /oauth2/v2.0/token端点上的客户端凭据流请求令牌时,在jwt令牌声明中包含来自client_app的信息。
这是一个令牌请求:
POST /<tenant id>/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
 
client_id=<Application ID of client_app>
&client_secret=<secret of client_app>
&scope=<Application ID URI of main_app + "/.default">
&grant_type=client_credentials

令牌请求的响应是一个有效的令牌,其中包括roles(从main_app授予给client_app的应用程序角色),audsubidtype: app声明。 但我的可选声明丢失了

MS docs指出,使用目录扩展可以包括可选声明。

模式和开放扩展不支持可选声明,只有 AAD-Graph 风格的目录扩展支持该功能。此功能可用于附加您的应用可以使用的其他用户信息[...]

因此,我尝试将目录扩展添加到我的 main_app extension_<main_app ID>_someAttrName),向 main_app 添加了一个可选声明,并在 client_app 中存储了这个目录扩展的值。 不幸的是,扩展值未反映在令牌中。

我尝试在client_app本身上添加目录扩展名(extension_<client_app ID>_someAttrName),并使用ClaimsMappingPolicy将目录扩展名映射到main_app。不幸的是,扩展值没有反映在令牌中。

在我看来,这些声明缺失了,因为它们不是来自用户对象。MS文档提供了很多添加可选声明的信息,但大多数情况涉及用户。例如,清单的可选声明source属性:

声明的源(目录对象)。有预定义的声明和来自扩展属性的用户定义的声明。如果源值为null,则声明是预定义的可选声明。如果源值为用户,则名称属性中的值是来自用户对象的扩展属性。

据我了解,仅支持null"user"。我想包括源自应用程序注册(client_app)的目录扩展名。由于我必须使用客户端凭据流(服务器到服务器),因此没有用户参与。

那么,在使用客户端凭据流时,如何向令牌添加自定义可选声明,而不涉及任何用户对象?有一个应用程序对象参与其中。那么,我需要如何配置声明才能反映自定义应用程序数据(例如,目录扩展名)?

main_app的清单:

{
    "id": "<main_app ID>",
    "acceptMappedClaims": true,
    "accessTokenAcceptedVersion": 2,
    "appId": "<main_app APP ID>",
    "appRoles": [{
            "allowedMemberTypes": ["Application"],
            "isEnabled": true,
            "origin": "Application",
            "value": "readAll"
        },{
            "allowedMemberTypes": ["Application"],
            "isEnabled": true,
            "origin": "Application",
            "value": "writeAll"
        }],
    "identifierUris": ["api://<main_app ID>"],
    "optionalClaims": {
        "idToken": [],
        "accessToken": [            {
                "name": "extension_<main_app ID>_someAttrName",
                "source": "application", <-- propably invalid, "user" or null is supported
                "essential": false,
                "additionalProperties": []
            }, { ... }
        ],
    },
} /# trunced for readability

客户端应用的清单:
{
    "id": "<client_app ID>",
    "accessTokenAcceptedVersion": null,
    "appId": "<client_app APP ID>",
    "passwordCredentials": [{...}],
    "extension_<main_app ID>_someAttrName": "some-string-value"
} /# trunced for readability

我的ClaimsMappingPolicy 定义 如下:

"ClaimsMappingPolicy": { "Version": 1, "IncludeBasicClaimSet": "true",
        "ClaimsSchema": [ {
            "Source": "application",
            "ExtensionID": "extension_<client_app ID>_someAttrName",
            "JwtClaimType": "someAttrName"
        } ]
}

你有没有找到解决这个需求的方法?我也有和你一样的需求。 - Saravana Kumar
@SaravanaKumar 我刚刚回答了自己的问题。 - Dan
嗨,我有同样的问题,我想在声明列表中至少返回客户端应用程序名称,但找不到方法来实现它。我觉得这种行为相当恼人...谢谢您的调查。 - kavanka
1个回答

2

我联系了Azure支持工程师,他们告诉我,无法包含来自应用程序注册的基于目录扩展的声明。他们没有详细说明,但回复如下:

很抱歉通知您,我们得知在JWT令牌中反映扩展声明将不可能。因为无法将目录扩展添加到servicePrincipal对象中。

我假定使用客户端凭据流时,请求实体是服务主体。


嗨@Daniel。我有和你一样的用例,而且我也遇到了你所遇到的问题,听到这个结论太糟糕了。 请问你已经就此做出了什么决定吗?你是否继续使用AAD应用程序进行OAuth客户端凭据,而不在令牌中使用自定义声明,或者你采取了其他方法或使用了不同的服务提供商?谢谢。 - Alexandre Ribeiro
1
目前,我们使用应用程序注册清单(目录扩展)中存储的信息。在身份验证过程中,我们通过 Graph API 请求这些值,但是在我看来,这远非理想。这会带来额外的请求,因此性能降级。如果这些数据存储在访问令牌内部,将会更好。如果您有更好的解决方案,请告诉我。 - Dan
嗨,我想知道你在这个解决方案上有没有取得任何进展,或者你还在调用图形 API 吗?如果是这样,从清单中检索信息的图形 API 端点是什么? - user1784297
我曾经调用过GraphApi端点 GET /applications/:id 文档。我的数据变得更加复杂,清单已经不再足以存储它了。因此,我将我的数据移动到CosmosDB中,并在身份验证过程中检索它。最终,我没有成功将数据获取到JWT令牌中。现在,我只使用该令牌进行身份验证。 - Dan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接