自动创建Azure AD Web App密钥

时间:2016-10-28 19:49:50

标签: powershell azure azure-active-directory auth0

我们编写了一组Powershell脚本,以自动化在Azure环境中创建Web应用程序新实例的过程。这些脚本的一部分使用Graph API创建一些Azure AD对象,以及Auth0中的相应对象,我们将其用于单点登录。到目前为止,我们还没有成功地以编程方式为AAD应用程序创建新密钥。我们已经尝试了很多方法,虽然我们可以看到生成的应用程序确实有一个Key(并且Auth0中的连接对象在其Client Secret字段中有该键),但我们在尝试进行身份验证时始终会收到此错误:

error message

到目前为止,我们已经授权访问应用程序以进行单点登录并读取AAD中的目录数据。 (编辑:我们通过手动跟踪provisioning_ticket_URL来执行此操作,该配置是Auth0 API调用返回的对象的一部分,用于创建Connection对象。此URL提示我们输入Azure凭据,然后显示此页面: grantaccess

在我们通过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"
        }
      ]
    }
  ]
}

1 个答案:

答案 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)创建应用程序时,不会创建这些对象,这会导致您在尝试进行身份验证时看到的错误。

此处的解决方案是,在您能够让其他人登录该应用程序之前,您需要与租户的管理员进行一次交互式登录体验。在此登录体验期间,您必须获得管理员对您的应用及其所需权限的同意。在获得此一次性同意后,您应用程序的后续呼叫不应要求同意,并且您不会遇到您遇到的问题。

总结如下:

  1. 使用您想要的任何方法自动创建应用
  2. 然后使用您的应用程序信息,并使用查询字符串“prompt = admin_consent”
  3. 与管理员创建交互式登录
  4. 然后使用您的应用,但您希望它可以正常工作
  5. 谢谢! Shawn Tabrizi