Azure-Samples / active-directory-dotnet-graphapi-web

A .NET 4.5 MVC web app that demonstrates how to query the Azure AD Graph API using the Azure AD Graph Client Library
82 stars 68 forks source link

AAD: app to app-permissions is not created properly #35

Closed RCTycooner closed 6 years ago

RCTycooner commented 8 years ago

Hi,

I'm using this library to register 2 applications (a web api, and a windows10-UWP client app) into my AAD.

I first create the web api as followed:

        Application appObject = new Application { DisplayName = displayName };
        appObject.IdentifierUris.Add(identifierUri);
        appObject.ReplyUrls.Add(replyURL);
        appObject.Homepage = replyURL;
        appObject.AvailableToOtherTenants = false;

        appObject.GroupMembershipClaims = "All";
        appObject.ObjectType = "Application";

        // created Keycredential object for the new App object
        PasswordCredential pwdCredential = new PasswordCredential
        {
            StartDate = DateTime.UtcNow,
            EndDate = DateTime.UtcNow.AddYears(2),
            Value = secret,
        };
        appObject.PasswordCredentials.Add(pwdCredential);

        var AADAccess = new RequiredResourceAccess();
        AADAccess.ResourceAppId = "00000002-0000-0000-c000-000000000000";

        AADAccess.ResourceAccess.Add(new ResourceAccess()
        {
            //"Read directory data"
            Id = Guid.Parse("5778995a-e1bf-45b8-affa-663a9f3f4d04"),
            Type = "Role,Scope",
        });
        AADAccess.ResourceAccess.Add(new ResourceAccess()
        {
            //"Sign in and read user profile"
            Id = Guid.Parse("311a71cc-e848-46a1-bdf8-97ff7156d8e6"),
            Type = "Scope",
        });
        AADAccess.ResourceAccess.Add(new ResourceAccess()
        {
            //"Access the directory as the signed-in user"
            Id = Guid.Parse("a42657d6-7f20-40e3-b6f0-cee03008a62a"),
            Type = "Scope",
        });
        appObject.RequiredResourceAccess.Add(AADAccess);

        activeDirectoryClient.Applications.AddApplicationAsync(appObject).Wait();

This creates the application just fine, it also implicitly creates an "user_impersonation"-claim.

I then retrieve this user_impersonation-claim's Id (and the app id) as followed:

var webapiClientId = tenantWebApp.AppId;
var webapiUserAccessClaimId = tenantWebApp.Oauth2Permissions.Where(s => s.Value == "user_impersonation").Select(s => s.Id).FirstOrDefault();

This application is now visible in the management portal in the AAD. Everything in the "Configuration"-tab looks fine.

Then I create the client application as followed:

        Application appObject = new Application { DisplayName = displayName };
        appObject.ReplyUrls.Add("ms-app://TEMP/");
        appObject.ObjectType = "Application";
        appObject.PublicClient = true; //"Native Client App"
        appObject.AvailableToOtherTenants = true;
        //  Add the proper rights to the AAD
        var AADAccess = new RequiredResourceAccess();
        AADAccess.ResourceAppId = "00000002-0000-0000-c000-000000000000";

        AADAccess.ResourceAccess.Add(new ResourceAccess()
        {
            //"Sign in and read user profile"
            Id = Guid.Parse("311a71cc-e848-46a1-bdf8-97ff7156d8e6"),
            Type = "Scope",
        });
        appObject.RequiredResourceAccess.Add(AADAccess);

        //  Add the proper rights to the Tenant Web API
        var AADAccess2 = new RequiredResourceAccess();
        AADAccess2.ResourceAppId = webapiClientId;

        AADAccess2.ResourceAccess.Add(new ResourceAccess()
        {
            //Our "user_impersonation"-claim.
            Id = webapiUserAccessClaimId,
            Type = "Scope",
        });
        appObject.RequiredResourceAccess.Add(AADAccess2);

        activeDirectoryClient.Applications.AddApplicationAsync(appObject).Wait();

As you can see, the client application is given access to the web api by the "user_impersonation"-claim.

Now, when verifying this in the management portal, the application is present. HOWEVER, in the "configuration"-tab, near the bottom with "permissions to other applications", I see this: " Delegated Permissions: 0" instead of " Delegated Permissions: 1"

I can't open the dropdown at "Delegated Permissions" and can't select the user_impersonation-claim.

Now, the funny thing is, when I go to the web api's configuration in the AAD and change anything (e.g. add a reply url "http://tmp") and press "Save". The client's permissions are now OK !

Is there anything I'm missing or am I doing something in the wrong order?

pauldalyii commented 8 years ago

I'm facing similar issues in trying to automate the provisioning of two Azure AD Apps (an API & headless client of the API). I'm using the active-directory-dotnet-graphapi-console example to try to piece this together.

I can't seem to get past the activeDirectoryClient.Oauth2PermissionGrants.AddOAuth2PermissionGrantAsync(permissionObject).Wait(); call in the Create New Permission region. At first I got exceptions about having an invalid ResourceID. When I changed the ResourceIdto 00000002-0000-0000-c000-000000000000 per what I'm seeing when I download manifest files for Apps I configure manually via the portal, the invalid ResourceIdexception is replaced with a generic an error has occurred exception.

Were you able to get any further with this?

Thanks!

RCTycooner commented 8 years ago

I've noticed that the OAuth's permission was automatically created by the underlying API for me. (I tried to create an "user_impersonation"-permission manually at first, but couldn't. It threw some error (I don't recall the specific message), but if I omitted that, a user_impersonation-grant was automatically created for my web-app.

I was then able to retrieve this by calling: Guid webapiUserAccessClaimId = tenantWebApp.Oauth2Permissions.Where(s => s.Value == "user_impersonation").Select(s => s.Id).FirstOrDefault(); with "tenantWebApp" is an "Application" object from the graph api.

In order to actually grant access to (for example) the AAD, I had to add a RequiredResource (as you can also see in my code in the original post). Perhaps you need to do this, instead of adding it to the OAuth2PermissionGrants ?

My actual problem (that I still need to 'refresh' the web app in AAD by editing and saving it) still remains unsolved. For now, we shipped it with this workaround.

pallablahiri-okta commented 7 years ago

@RCTycooner I am also having the similar issue and wonder when this will be resolved "My actual problem (that I still need to 'refresh' the web app in AAD by editing and saving it) still remains unsolved. "

Here is my observations:

  1. Created the App with RequiredResource using Graph api. with "requiredResourceAccess": [ { "resourceAppId": "00000003-0000-0000-c000-000000000000", "resourceAccess": [ { "id": "741f803b-c850-494e-b5df-cde7c675a1ca", "type": "Role" } ] } ],
  2. Noticed that no corresponding ServicePrincipal was created for the app, so created the SP for the appId from #1 and with same display name.
  3. Still got 403
  4. had to go to portal and edit something (e.g identifierUrls) and save.
  5. noticed that saving from portal created an AppRoleAssignmentI. So added AppRoleAssignment as well via API (same as it gets created after the save via portal). Still 403.

Wonder what other object(s) gets created behind the scene here. I compared the application manifest (after creating it via api #1) with the one after saving the same application in AAD (#4) did not see any difference there. Love to hear about a work-around (w/o needing to go to AAD portal).

RCTycooner commented 7 years ago

Hi @pallablahiri-okta, got your ping on my site. I have no idea if this issue is being worked on or not. I'm still using the above workaround myself.

If I hear anything about this, I'll let you know here.

pallablahiri-okta commented 7 years ago

@RCTycooner Thanks! Any updates from MSFT would be highly appreciated @vibronet can you please comment on this.

pallablahiri-okta commented 7 years ago

@RCTycooner I guess I found the reason. "you can't register a new application using the Graph API from an unregistered client." find more details here http://stackoverflow.com/questions/23133014/connect-to-azure-to-create-an-application-registration. AAD portal is a registered client so it works.

RCTycooner commented 7 years ago

Hi @pallablahiri-okta, I'm actually using a registered client.

RCTycooner commented 6 years ago

Minor update about my findings for this bug:

Is there any new information about this issue available? I'd like to get this fixed before the old portal is no longer available...

RCTycooner commented 6 years ago

Fixed this by doing two things differently:

  1. In order to read the logged in users groups, we need access to the Microsoft Graph. You can do this programmatically by adding the following Required Resource: var graphAccess = new RequiredResourceAccess() { ResourceAppId = "00000003-0000-0000-c000-000000000000" }; //Read directory and Read all groups (don't know which one is which, whatever) graphAccess.ResourceAccess.Add(new ResourceAccess() { Id = Guid.Parse("7ab1d382-f21e-4acd-a863-ba3e13f7da61"), Type = "Role", }); graphAccess.ResourceAccess.Add(new ResourceAccess() { Id = Guid.Parse("5b567255-7703-4780-807c-7be8301ae99b"), Type = "Role", });

  2. Grant admin consent via the following URL: https://login.microsoftonline.com/{0}/oauth2/authorize?client_id={1}&response_type=code&redirect_uri={2}&nonce=1234&resource=https://graph.windows.net&prompt=admin_consent {0} = YourAAD (e.g. AAD.onmicrosoft.com) {1} = The clientId for the application receiving the above resource-access. {2} = A callback url on your web app.

Apparently, the old portal assigned this access and the consent implicitly. That explained why the above workaround works...