【问题标题】:Azure AD Graph API - Assigning a group with role to a tenant's application (ServicePrincipal)Azure AD Graph API - 将具有角色的组分配给租户的应用程序 (ServicePrincipal)
【发布时间】:2016-12-15 16:48:50
【问题描述】:

全部,

我正在尝试将组分配给租户中的应用程序(我的公司不拥有该应用程序,Box)。我从下载了 Graph Console App V3 https://github.com/Azure-Samples/active-directory-dotnet-graphapi-console 并查看了代码。我下面的代码似乎遵循了这个例子,唯一的区别是我想把这一切作为应用程序来做,而不需要用户同意。当我尝试在“应用程序模式”下运行控制台应用程序时,它会因权限问题而失败。所以,我只是写了下面的代码,没有遇到权限问题,但又遇到了另一个错误(请参阅我的 cmets inline)。

我使用的是 Java,而不是 .NET,但我想使用 Fiddler 来查看请求是什么,因为我在使用 Java 手动创建请求时运气不佳。

不过,我在使用 Microsoft.Azure.ActiveDirectory.GraphClient 的 .NET 中也没有任何运气。这是我的代码。我的租户有一个单租户公司拥有的应用程序,其应用程序权限授予“Windows Azure Active Directory”。

try
{

    var servicePrincipals = await client.ServicePrincipals.ExecuteAsync();
    var servicePrincipal = (ServicePrincipal)servicePrincipals.CurrentPage
        .SingleOrDefault(sp => sp.AppDisplayName == "Box");

    while (servicePrincipal == null && servicePrincipals.MorePagesAvailable)
    {
        await servicePrincipals.GetNextPageAsync();
        servicePrincipal = (ServicePrincipal)servicePrincipals.CurrentPage
            .SingleOrDefault(sp => sp.AppDisplayName == "Box");
    }

    if (servicePrincipal != null)
    {
        var spfetcher = (servicePrincipal as IServicePrincipalFetcher);

        // returns the correct information and all guids align properly with the correct servicePrincipal,
        // Id (appRole) and principalId for the group
        var appRoleAssignments = await spfetcher.AppRoleAssignedTo.ExecuteAsync();

        // data returned by call above
        //CreationTimestamp         null
        //Id                        {efxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
        //PrincipalDisplayName      "TestGroup"
        //PrincipalId               {39xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
        //PrincipalType             "Group"
        //ResourceDisplayName       "Box"
        //ResourceId                {11xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}


        // I have a group called "Manually Added" that want to assign to this application with
        // the first role that the service principal has
        var groups = await client.Groups.ExecuteAsync();
        var group = (Group)groups.CurrentPage.SingleOrDefault(g => g.DisplayName.Contains("Manual"));
        while (group == null && groups.MorePagesAvailable)
        {
            await groups.GetNextPageAsync();
            group = (Group)groups.CurrentPage.SingleOrDefault(g => g.DisplayName.Contains("Manual"));
        }

        if (group != null)
        {
            // Tried this way, seems to be correct as far as the documentation and examples
            AppRoleAssignment appRoleAssignment = new AppRoleAssignment();

            // just use a known appRole id for this example
            appRoleAssignment.Id = servicePrincipal.AppRoles.FirstOrDefault().Id;

            // the service principal to add the group with the app role
            appRoleAssignment.ResourceId = Guid.Parse(servicePrincipal.ObjectId);

            // principal is a group (named ManuallyAdded)
            appRoleAssignment.PrincipalType = "Group";

            // the id of the group (ManuallyAdded)
            appRoleAssignment.PrincipalId = Guid.Parse(group.ObjectId);

            // Tried this way, no luck Bad Request (400) with "not a valid reference update"
            servicePrincipal.AppRoleAssignments.Add(appRoleAssignment);
            await servicePrincipal.UpdateAsync();

            // Tried this way, same thing as above
            //var spfetcher = (servicePrincipal as IServicePrincipalFetcher);
            //var appRoleAssignments = await spfetcher.AppRoleAssignedTo.ExecuteAsync();
            await spfetcher.AppRoleAssignments.AddAppRoleAssignmentAsync(appRoleAssignment);

            // Tried this way, same thing as above
            // var groupFetcher = (group as IGroupFetcher);
            // await groupFetcher.AppRoleAssignments.AddAppRoleAssignmentAsync(appRoleAssignment);

            // Tried flipping the resourceId and the principalId, to assign the app through the group 
            // AddAppRoleAssignmentAsync.  Same error
            //appRoleAssignment = new AppRoleAssignment();
            //appRoleAssignment.Id = servicePrincipal.AppRoles.FirstOrDefault().Id;
            //appRoleAssignment.ResourceId = Guid.Parse(group.ObjectId);
            //appRoleAssignment.PrincipalType = "Group";
            //appRoleAssignment.PrincipalId = Guid.Parse(servicePrincipal.ObjectId);

            //// Tried this way, same thing as above
            //var groupFetcher = (group as IGroupFetcher);
            //await groupFetcher.AppRoleAssignments.AddAppRoleAssignmentAsync(appRoleAssignment);     
        }
    }
}
catch (Exception e)
{
    Program.WriteError("Error: {0}", Program.ExtractErrorMessage(e));
}

在 Azure 中授予的权限:

谢谢! 布赖恩

更新

这是我的访问令牌中的内容

{
  "aud": "https://graph.windows.net",
  "iss": "https://sts.windows.net/<tenantId>/",
  "iat": 1480449285,
  "nbf": 1480449285,
  "exp": 1480453185,
  "appid": "<appId>",
  "appidacr": "1",
  "e_exp": 10800,
  "idp": "https://sts.windows.net/<tenantId>/",
  "oid": "xxxxxx-0b62-4d91-8853-xxxxxxxxxxxx",
  "roles": [
    "Device.ReadWrite.All",
    "Directory.Read.All",
    "Member.Read.Hidden",
    "Directory.ReadWrite.All",
    "Domain.ReadWrite.All"
  ],
  "sub": "xxxxxx-0b62-4d91-8853-xxxxxxxxxxxx",
  "tid": "<tenantId>",
  "ver": "1.0"
}

这是引发权限问题的代码(这是我在上面链接的 graphapi-console 中找到的修改代码),但调用了 GraphRequest.cs 中的现有方法

 // the exception occurs in CreateNewApplication.  
 // But in my case, I have already loaded the existing servicePrincipal
 var newApp = await CreateNewApplication(client);
 var newServicePrincipal = await CreateServicePrincipal(client, newApp);
 await AssignAppRole(client, newApp, newServicePrincipal);

什么原因:

{
  "odata.error": {
    "code": "Authorization_RequestDenied",
    "message": {
      "lang": "en",
      "value": "Insufficient privileges to complete the operation."
    }
  }
}

【问题讨论】:

  • 您能否分享您的访问令牌中的范围声明“scp”?您还可以在遇到权限问题的流程中分享相同的信息吗?
  • 我已更新我的问题以添加访问令牌信息和导致权限异常的请求代码。 @ShawnTabrizi

标签: azure azure-active-directory azure-ad-graph-api


【解决方案1】:

这是我最终想出的完整答案。

用于创建 appRoleAssignment:

private static final String RESOURCE_BASE_URL = "https://graph.windows.net";
private static final String GROUPS_RESOURCE_SET = "groups";
private static final String PRINCIPAL_TYPE = "Group";
// use this if you want to assign a User
// private static final String PRINCIPAL_TYPE = "User";

private static final String API_VERSION = "api-version=1.6";

private String tenantName = "<your tenant name (domain) or id>"
private String appRoleId = "<some appRoleId (from the applications appRoles list or Empty UUID>"
private String servicePrincipalId = "<your servicePrincipalId for the assignment>"
private String principalId = "<your user or group id>"

// empty UUID for appRoleId means no app roles initially (default access)
String postData = String.format(
    "{\n" +
            "\"id\": \"%s\"," +
            "\"principalId\": \"%s\"," +
            "\"principalType\": \"%s\"," +
            "\"resourceId\": \"%s\"" +
            "}", appRoleId, principalId,
    PRINCIPAL_TYPE, servicePrincipalId);

String urlString = String.format("%s/%s/%s/%s/appRoleAssignments?%s", RESOURCE_BASE_URL,
        tenantName, GROUPS_RESOURCE_SET, <group objectId>, API_VERSION);

在我的租户上以编程方式创建应用程序的权限问题令人困惑。经过大量搜索后,应用程序(服务主体)似乎需要具有公司管理员角色(或具有足够权限的角色)。我无法通过门户或 AD Graph API 来完成,尽管可能有办法做到这一点。相反,您似乎必须使用 Powershell 脚本。我在几个地方(不同的变体)在网上找到了这个,经过反复试验,缩小到这个范围。

# -------------------------------
# Connect and request credentials
# --------------------------------
Connect-MsolService

# ------------------------------------------------
# Get the service principal objectId for the specified app
# -----------------------------------------------
$appDisplayName = "<your app name>"
$objectId = (Get-MsolServicePrincipal -SearchString $appDisplayName).ObjectId

# ------------------------------------------------
# Assign the company admin role to the service principal
# -----------------------------------------------
$tenantRoleName = "Company Administrator"              
Add-MsolRoleMember -RoleName $tenantRoleName -RoleMemberType ServicePrincipal -RoleMemberObjectId $objectId

安装哪个模块有点令人困惑。我准确地找到了获得正确 cmdlet 所需的内容。似乎 MSOnline 模块提供了运行此脚本所需的一切。如果没有出现错误,请安装 AzureAD 模块(或 AzureADPreview 模块)。这些是我发现的最佳步骤:https://docs.microsoft.com/en-us/powershell/msonline/

布赖恩

【讨论】:

    【解决方案2】:

    将角色分配给特定组的应用程序。我们需要更新特定的 Group 而不是 Application。以下是供您参考的请求:

    POST: https://graph.windows.net/xxx.onmicrosoft.com/directoryObjects/{GroupId}/Microsoft.DirectoryServices.Group/appRoleAssignments?api-version=1.6
    Authorization: Bearer {token}
    {
        "id": "{roleId}",
        "odata.type":"Microsoft.DirectoryServices.AppRoleAssignment",
        "principalId":"{groupId}",
        "principalType":"Group",
        "resourceId":"{principalId}"
    }
    

    更新

    要修复关于权限不足以完成操作的403错误,我们需要使用下面的命令,使用Azure ActiveDirectory (MSOnline)公司管理员角色分配给应用。

    Connect-MsolService
    $ClientIdWebApp = '{your_AD_application_client_id}'
    $webApp = Get-MsolServicePrincipal –AppPrincipalId $ClientIdWebApp
    #use Add-MsolRoleMember to add it to "Company Administrator" role).
    Add-MsolRoleMember -RoleName "Company Administrator" -RoleMemberType ServicePrincipal -RoleMemberObjectId $webApp.ObjectId
    

    【讨论】:

    • 这对我上面的问题部分正确。这处理了添加 appRole 分配的情况,但不适用于创建应用程序时拒绝访问的情况。
    • 根据测试,为了解决这个问题,我们可以将公司管理员角色分配给应用程序。我修改了帖子附加了分配这个角色的命令,你可以检查它是否有帮助。
    • 我希望我们可以在 Azure AD 中获得更多权限来做事。必须让服务主体成为公司管理员是一件很糟糕的事情。
    • @juunas 如果您对 Azure 有任何想法或反馈,可以通过here 提交。
    猜你喜欢
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    相关资源
    最近更新 更多