Azure AD Graph API - 将具有角色的组分配给租户的应用程序(ServicePrincipal)

时间:2016-11-29 19:40:02

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

所有

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

我使用的是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中授予的权限:

Permissions granted in 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."
    }
  }
}

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

以下是我最终提出的完整答案。

用于创建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 moldule),如果出现错误。这些是我找到的最佳步骤:https://docs.microsoft.com/en-us/powershell/msonline/

布赖恩