我们编写了一组Powershell脚本,以自动化在Azure环境中创建Web应用程序新实例的过程。这些脚本的一部分使用Graph API创建一些Azure AD对象,以及Auth0中的相应对象,我们将其用于单点登录。到目前为止,我们还没有成功地以编程方式为AAD应用程序创建新密钥。我们已经尝试了很多方法,虽然我们可以看到生成的应用程序确实有一个Key(并且Auth0中的连接对象在其Client Secret字段中有该键),但我们在尝试进行身份验证时始终会收到此错误:
到目前为止,我们已经授权访问应用程序以进行单点登录并读取AAD中的目录数据。 (编辑:我们通过手动跟踪provisioning_ticket_URL来执行此操作,该配置是Auth0 API调用返回的对象的一部分,用于创建Connection对象。此URL提示我们输入Azure凭据,然后显示此页面:
)
在我们通过Azure门户为应用程序手动创建新密钥,保存应用程序并将新创建的密钥复制到Auth0连接之前,此错误仍然存在。这样做总能解决问题,但我们希望避免这一额外步骤。
在我们在API调用中创建的AAD应用程序的主体中,我们有此部分定义了键:
"passwordCredentials":
[
{
"startDate": "2016-10-28T20:40:32Z",
"endDate": "2017-10-29T20:40:32Z",
"keyId": "(a GUID)",
"value": "(a Base64 string)"
}
],
对于这些值,我们尝试以很多不同的方式生成它们,它接受API PUT调用的值,但是当我们尝试登录时它们仍然给我们相同的错误。例如,我们尝试的一种方法是从$ appKeyGUID和$ appKeyValue中插入值:
$appKeyGUID = [guid]::NewGuid()
$guidBytes = [System.Text.Encoding]::UTF8.GetBytes($appKeyGUID)
$appKeyValue = [System.Convert]::ToBase64String($guidBytes);
分别进入keyID和value。我在其他地方读过,这个值应该是44个字符长,但这个不会是。
但似乎价值本身可能不是问题。我尝试通过Azure门户生成密钥,使用Graph API GET调用来检索keyId,然后将这两个确切的值硬编码到应用程序正文中,但登录仍会产生相同的错误。
知道我哪里出错了?
编辑:根据Philippe的建议,我尝试通过门户网站仅更改AD应用程序的显示名称,这确实解决了问题。这让我认为,在通过门户网站保存时,应用程序正在修复的其他地方可能出现了问题。我在执行手动保存之前和之后检查了清单,确实存在一个小的区别:在RequiredResourceAccess部分(我从这里学习http://www.cloudidentity.com/blog/2015/09/01/azure-ad-permissions-summary-table/和https://www.microsoftpressstore.com/articles/article.aspx?p=2473127&seqNum=2)中,我有这个:< / p>{
"id": "5778995a-e1bf-45b8-affa-663a9f3f4d04",
"type": "Role"
},
{
"id": "5778995a-e1bf-45b8-affa-663a9f3f4d04",
"type": "Scope"
}
而不是这个,门户网站将其更改为
{
"id": "5778995a-e1bf-45b8-affa-663a9f3f4d04",
"type": "Role,Scope"
},
所以我改变了我们发送的身体以匹配第二种格式。不幸的是,我们仍然遇到了相同的错误。此外,我验证了在门户网站上进行保存之前和之后清单现在是相同的,就像应用程序上的API GET调用返回的正文一样。除了应用程序的定义之外,门户网站保存的内容必须是 else 。
之后,我尝试使用Graph API执行两次PATCH调用以将显示名称更新为某些内容,然后将其更改回来,希望它的行为类似于通过门户网站执行并修复问题。我通过门户网站验证了PATCH调用确实正在改变应用程序的显示名称。可悲的是,似乎那些编辑没有解决问题,我仍然得到原始错误。
我们使用Graph API调用创建应用程序,如下所示:
$uri = "https://graph.windows.net/$waadTenant/applications?api-version=1.6"
$newADApp = (Invoke-RestMethod –Uri $uri –Headers $authHeader –Method POST -Body $newappbody –Verbose)
这是我们最终用于定义应用程序的$ newappbody。我留下了一些硬编码的东西用于故障排除:
{
"odata.type": "Microsoft.DirectoryServices.Application",
"displayName": "customer1",
"homepage": "https://customer1.(our tenant).com",
"identifierUris":
[
"https://customer1.(our tenant).com"
],
"replyUrls":
[
"https://(our tenant).auth0.com/login/callback"
],
"passwordCredentials":
[
{
"startDate": "(a hardcoded date)",
"endDate": "(a hardcoded date)",
"keyId": "(hardcoded GUID that was previously generated by the portal and extracted through an API GET)",
"value": "(hardcoded Base64 like above)"
}
],
"requiredResourceAccess":
[
{
"resourceAppId": "00000002-0000-0000-c000-000000000000",
"resourceAccess":
[
{
"id": "5778995a-e1bf-45b8-affa-663a9f3f4d04",
"type": "Role,Scope"
},
{
"id": "311a71cc-e848-46a1-bdf8-97ff7156d8e6",
"type": "Scope"
},
{
"id": "6234d376-f627-4f0f-90e0-dff25c5211a3",
"type": "Scope"
}
]
}
]
}
答案 0 :(得分:2)
这里的最终问题似乎与申请同意有关。 我将在这里详细介绍,但请随时快速阅读本文档,其中描述了我们的同意框架: https://azure.microsoft.com/en-us/documentation/articles/active-directory-integrating-applications/
您在应用程序清单中显示的内容与您的应用程序配置相关,但是,您的应用程序的同意记录将不会在那里找到,因此我认为您的“a / b”测试不会有成效。
我认为您在这里找到的是Azure门户在后台有一些“魔力”,如果您是管理员并保存应用程序,它将同意您的应用程序。当您在门户中从头到尾注册应用程序时(再次,作为管理员),我们会在您保存应用程序后自动记录您的同意。这在后台发生,并且生成的“对象”是:您租户中应用的服务主体,以及您作为用户和服务主体之间的同意链接。创建的链接特别是“管理员租户范围内的同意”对象,如果您将“prompt = admin_consent”作为查询字符串添加到您的登录URL,则会获得同样的效果。
使用其他方法(如Graph API或AAD PowerShell)创建应用程序时,不会创建这些对象,这会导致您在尝试进行身份验证时看到的错误。
此处的解决方案是,在您能够让其他人登录该应用程序之前,您需要与租户的管理员进行一次交互式登录体验。在此登录体验期间,您必须获得管理员对您的应用及其所需权限的同意。在获得此一次性同意后,您应用程序的后续呼叫不应要求同意,并且您不会遇到您遇到的问题。
总结如下:
谢谢! Shawn Tabrizi