Microsoft graph API: permission grant for application (app roles) (NOT delegate via Oauth2PermissionGrants) - azure-active-directory

We are using the Microsoft graph API (.net SDK).
We know that we can use GraphServiceClient.Oauth2PermissionGrants for delegated grant (in Azure AD app it's "Expose an API").
But when it comes to granting admin consent for application type (via app role of other applications), like below:
In the portal, we can just click "Grant admin consent for XXXX".
I could not figure out how to GraphServiceClient.PermissionGrants does not seem to be the one we are after.

Googled around, found the related answer Azure OAuth: Unable to programmatically create app with admin consent for permissions , which leads me to the actual API used https://learn.microsoft.com/en-us/graph/api/serviceprincipal-post-approleassignedto?view=graph-rest-1.0&tabs=csharp
In a nutshell, use app role assignment via AppRoleAssignedTo:
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var appRoleAssignment = new AppRoleAssignment
{
PrincipalId = Guid.Parse("THE-OBJECT-ID-OF-THE-PRINCIPAL-OF-THE-AZURE-AD-APPLICATION-THAT-NEEDS-ACCESS"),
ResourceId = Guid.Parse("THE-OBJECT-ID-OF-THE-PRINCIPAL-OF-THE-AZURE-AD-APPLICATION-THAT-HAS-THE-APP-ROLE-DEFINED"),
AppRoleId = Guid.Parse("THE-ID-OF-THE-APP-ROLE-DEFINED-IN-THE-RESOURCE-ID-ABOVE")
};
await graphClient.ServicePrincipals["THE-OBJECT-ID-OF-THE-PRINCIPAL-OF-THE-AZURE-AD-APPLICATION-THAT-HAS-THE-APP-ROLE-DEFINED"].AppRoleAssignedTo
.Request()
.AddAsync(appRoleAssignment);

Related

How to get the resourceId when granting an appRoleAssignment to a ServicePrincipal in Azure AD?

I am trying to Grant Admin Consent of a API in an Azure AD application through Graph API. I created the App, created its Client Secret, then created a Service Principal to which I want to add AppRoleAssignment.
The API call to do so requires three attributes in the body (Documentation)
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var appRoleAssignment = new AppRoleAssignment
{
PrincipalId = {Input the Service Principal Id},
ResourceId = {? Where to get this value?},
AppRoleId = {Input the App role of the API I added to my Azure AD App}
};
await graphClient.ServicePrincipals["{servicePrincipal-id}"].AppRoleAssignments
.Request()
.AddAsync(appRoleAssignment);
My question is where to get the ResourceId from? Knowing that this is different from one tenant to the other.
Please note that if I grant the admin consent manually, then run this API call
var appRoleAssignments = GraphAppClient.ServicePrincipals[servicePrincipalId].AppRoleAssignments.Request().GetAsync().Result;
Then revoke the consent, get the ResourceId from what the API returned, and then use it in the original call, the admin consent works fine.
The documentation for the appRoleAssignment resource type says the following about the resourceId property:
The unique identifier (id) for the resource service principal for which the assignment is made.
A good approach to find a service principal in a tenant is to search the servicePrincipals collection, filtering on the appId or servicePrincipalName properties.For example, to search for the Microsoft Graph service principal by its identifier URI:
GET https://graph.microsoft.com/v1.0/servicePrincipals
?$filter=servicePrincipalNames/any(n:n eq 'https://graph.microsoft.com')
Or to find it by its appId:
GET https://graph.microsoft.com/v1.0/servicePrincipals
?$filter=appId eq '00000003-0000-0000-c000-000000000000'
With the Microsoft Graph SDK for .NET, this would look something like this:
var r = await graphServiceClient.ServicePrincipals
.Request()
.Filter("appId eq '00000003-0000-0000-c000-000000000000'")
.GetAsync();
Using Microsoft Graph PowerShell, things look very similar:
$r = Get-MgServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'"
Using the Azure portal, each app under "Enterprise apps" corresponds to a service principal, and the "Properties" page shows its object ID.
(Once you have the service principal, you can use its appRoles collection to see the list of app roles it publishes, often useful to get the app role's id, which you'll need for the appRoleId property.)
I ended up figuring it out. The resourceId of every set of permission you are trying to add is the objectId of the app in Entreprise Applications. It sounds very confusing, but if you are trying to add Graph API permissions, you need to go to enterprise applications, find GraphAPI, and then find its ObjectId. That is your resourceId.

How to use Azure AppRoles in Blazor Server with Azure Active Directory

I have an up and running .NET 5 Web-API with a Blazor Server Client in Production. I'd like to switch from Individual User Accounts to Azure AD using App Roles to authenticate specific Users in my Controllers. I found lots of Information regarding Webassembly but none for Blazor Server.
Has somebody a working Solution for a .NET 5/6 Web-Api with a Blazor Server Client and integrating Azure App Roles?
Apps are already registered in the Azure Portal and so forth, I just need to know how to pass the App Roles specific stuff to my API, so my Controller can work with the [Authorize("Admin")] stuff. I suspect it will use Bearer Tokens aswell.
Edit:
Thanks a lot for reading. So I figured out that if I use something like this in my Controller only using the [Authorize] Attribute without any roles:
var identities = HttpContext.User.Identities.ToList();
foreach (var item in identities)
{
if (item.RoleClaimType == "admin")
{
// return or do something
}
}
It would just work fine but there has to be some smoother solution for this or am I doing this completly wrong? When I look at the WASM Samples, they pick up the AppRoles with their token and the Controller simply can use the [Authorize(Roles = "xyz")] Attribute. What am I missing here? :/
Btw, this is how my Program.cs looks right now:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
builder.Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"admin";
options.TokenValidationParameters.RoleClaimType = "doku";
},
options => { builder.Configuration.Bind("AzureAd", options); });
Thank you guys/gals <3
Please check if the given references are of use in your case.
A SERVER API app can authorize users to access secure API endpoints with authorization policies for security groups, AAD Administrator Roles, and App Roles
In Program.cs of a SERVER app, specify the claim as roleclaim
example:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
},
options => { Configuration.Bind("AzureAd", options); });
Then you can use admin role on authorization controller to access
[Authorize(Roles = "admin")]
Here in App roles section you can see the configuration for both
server and client.
Edit the app role in the manifest editor in portal and then give
proper api permissions , expose scopes and grant permission for admin
consent >see Add app roles and get them from a token .And the
procedural logic must contain those scopes required by api.
Note : The appRoles manifest property of both the client and the
server Azure portal app registrations must include the same configured
roles.
Please check this for more detailed information which guides for both server and client apps.
Other references:
using-app-roles-with-AAD-blazor-server-client scenario | codemaze.com
quickstart-configure-app-expose-web-apis
quickstart-configure-app-access-web-apis

Add user to Directory role in azure active directory via Microsoft graph SDK\API

I've created an API project in dotNet to get some data from microsoft.graph using SDK.
I managed to get all the users and all groups and see the role of each user (like Billing administrator / Application administrator, etc.), but I can not find a way to update or change the role to a user or group through the SDK / API.
I guess right now this option is not supported through API / SDK. Am I right?
You can do a HTTP request to the directory role using role-id or role-templateid for adding the user:
POST /directoryRoles/{role-id}/members/$ref
POST /directoryRoles/roleTemplateId={roleTemplateId}/members/$ref
Example :
POST https://graph.microsoft.com/v1.0/directoryRoles/fe8f10bf-c9c2-47eb-95cb-c26cc85f1830/members/$ref
or
POST https://graph.microsoft.com/v1.0/directoryRoles/roleTemplateId=88d8e3e3-8f55-4a1e-953a-9b9898b8876b/members/$ref
Content-type: application/json
{
"#odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/UserObjectID"
}
You can use C# to add user to directory role :
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var directoryObject = new DirectoryObject
{
Id = "bb165b45-151c-4cf6-9911-cd7188912848"
};
await graphClient.DirectoryRoles["{directoryRole-id}"].Members.References
.Request()
.AddAsync(directoryObject);
Reference :
Add user to directory role
Directory Role Id's

How does an admin grant access to an app?

I have made a web app that using Microsoft Graph and the scopes profile, openid, email and User.Read. This works fine.
I now want to include offline_access, User.Read, Mail.Send, Calendars.ReadWrite, Directory.ReadWrite.All, Directory.AccessAsUser.All, User.Read.All, Files.ReadWrite.All, Files.Read, Files.ReadWrite, and Sites.Read.All scopes.
When trying to login I get the message:
You can't access this application.
Tutorial Sample App needs permission to access resources in your organisation that only an admin can grant. Please ask an admin to grant permission to this app before you can use it.
I registered the app at https://apps.dev.microsoft.com/ and have these Graph Permissions set:
Using PHP, I use the following
use Microsoft\Graph\Graph;
use Microsoft\Graph\Model;
const CLIENT_ID = 'xxx';
const CLIENT_SECRET = 'xxx';
const REDIRECT_URI = 'xxxx';
const AUTHORITY_URL = 'https://login.microsoftonline.com/common';
const AUTHORIZE_ENDPOINT = '/oauth2/v2.0/authorize';
const TOKEN_ENDPOINT = '/oauth2/v2.0/token';
const SCOPES = 'profile openid email offline_access User.Read Mail.Send Calendars.ReadWrite Directory.ReadWrite.All Directory.AccessAsUser.All User.Read.All Files.ReadWrite.All Files.Read Files.ReadWrite Sites.Read.All';
and to create the authorisationUrl
$authorizationUrl = $provider->getAuthorizationUrl();
So, how can I get admin to grant access?
In order to obtain Admin Consent, you need to have an Admin for the tenant authenticate against the /adminconsent. The prototype for this URL is (line-break for readability only):
https://login.microsoftonline.com/common/adminconsent?
client_id=[APPLICATION ID]&redirect_uri=[REDIRECT URI]
I've written a blog post on this that will help walk you through how this works: v2 Endpoint and Admin Consent.

Error AADSTS65001 but no consent prompt for just one user

I am writing a C# .NET app. It is connected to our service on Azure which is configured for using AAD. In turn, our service tries to make calls to Exchange via EWS.
This all worked fine for me until we recently deployed our service bits to a new Azure web app with new app registrations. They are all configured correctly and other developers on our team can authenticate with the service and use it as expected.
When I try to connect to the service, I get the following error:
AADSTS65001: The user or administrator has not consented to use the application with ID '61a8b794-7f67-4a01-9094-fcdd45693eaa'. Send an interactive authorization request for this user and resource.
Trace ID: ece7c5d0-2ecb-4096-a87a-2cd33271d65d
Correlation ID: 093b5935-3b06-4d76-91a9-6619bc179544
Timestamp: 2017-02-09 23:19:28Z
The consent prompt never appeared for me when trying to connect after deploying the new service.
I'm not sure what it is about my user account that causes this error to occur (it happens on multiple machines with my account) while others can connect successfully.
Here’s some of the code used to acquire the token in the service:
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
var upn = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn);
var email = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email);
var userName = upn != null ? upn.Value : email?.Value;
accessToken = bootstrapContext.Token;
ClientCredential clientCred = new ClientCredential("61a8b794-7f67-4a01-9094-fcdd45693eaa", appKey);
UserAssertion assertion = new UserAssertion(accessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/microsoft.onmicrosoft.com");
AuthResult = authContext.AcquireToken("https://outlook.office365.com", clientCred, assertion);
Any ideas why I wouldn't get the consent prompt, but other users on my team have?
Based on the description, you are developing multi-tier application using Azure AD.
Since you mentioned this issue was occurred after using the new app, did you config your new app as the knownClientApplications of your service app(61a8b794-7f67-4a01-9094-fcdd45693eaa)?
If yes, you should can give the consent for the service app when you sign-in your web app( refer here about multi-tier applications).
The problem why only you get this issue may others have given the consent to this app before.
Please let me know if it helps.

Resources