I'm trying to implement a search algorithm for our people using Microsoft Graph. What I would like to do is have 1 (not 2) instance of GraphServiceClient and use that to query People. Then, if no search results come up, I query the Users.
Currently, I use the delegated GraphServiceClient instance to use the people search, and I use the other application GraphServiceClient to search Users. But when I try to use the delegated GraphServiceClient to search Users, it gives me an unauthorized error.
Both use the same App ID registered into Microsoft so why can't I just have one instance instead of having 2 different instances? I've already received admin permissions to read our users. I just want to have 1 instance of Microsoft Graph. Not 2.
Edit: Here's the error message I get when trying to query users using a delegated GraphServiceClient instance:
Code: Authorization_RequestDenied\nMessage: Insufficient privileges to complete the operation.\n\nInner error\n
Found the answer. I just requested Directory.Read.All permissions from the user and I was able to access the list of Users to perform my search.
I don't even need application permissions anymore!
Related
How do I create a user using Microsoft graph? For I am having issues with regards to permission failures during a save.
I do have few questions in mind.
Where will the user be created by calling create user API in graph ? Is it in Azure AD or somewhere else ?
I tried calling create user api by passing json and required headers, below is the error I get
Where exactly do I need to set the permission, I have already added permissions in the Application Registration Portal
But when API is executed it shows that I don't have enough permission.
FYI, I have registered the app using the same email id that I am using to test the APIs here https://developer.microsoft.com/en-us/graph/graph-explorer#
If I am not the admin, where exactly do I need to set or request for it ?
In order to create a User via Microsoft Graph, you need to request either Directory.ReadWrite.All or Directory.AccessAsUser.All permission.
Important: Directory.ReadWrite.All and Directory.AccessAsUser.All both require Admin Consent before you can use them. If you're using Graph Explorer then the URI you need to provide your tenant Admin will be generated for you. If you're doing this in your own application, you'll need to construct an Admin Consent URI yourself. You can find more details on this at v2 Endpoint & Admin Consent.
Once you have the proper permissions configured (and consented), you'll want to POST the following JSON body/payload to https://graph.microsoft.com/v1.0/users:
{
"accountEnabled": true,
"displayName": "displayName-value",
"mailNickname": "mailNickname-value",
"userPrincipalName": "upn-value#tenant-name.onmicrosoft.com",
"passwordProfile" : {
"forceChangePasswordNextSignIn": true,
"password": "password-value"
}
}
This will create a user with a temporary password. The user will be asked to set a new password as after as they authenticate for the first time.
Where will the user be created by calling create user API in graph ?
Is it in Azure AD or somewhere else ?
Yes, the user created is in the Azure AD.
I tried calling create user api by passing json and required headers,
below is the error I get
For your error, have you added the request body like the following, and this required admin:
Where exactly do I need to set the permission, I have already added
permissions in the Application Registration Portal
The required permissions to create application:
For the details, please read here.
I am trying to build a list of emailadresses of all employees in our company.
This is in a Web App running on Azure, with Azure AD authentication. The app uses .NET Framework 4.6, and uses the Microsoft.Owin.Security packages to connect to Azure AD.
I can authenticate, I am authorized by my role as defined in the app registration. So far so good.
I can check out my own User Profile. This uses the Microsoft.Azure.ActiveDirectory.GraphClient package to build the queries, instead of manually creating the HTTPRequests.
string userObjectID = ClaimsPrincipal.Current
.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
async () => await authorizationHelper.GetTokenForApplication());
var result = await activeDirectoryClient.Users
.Where(u => u.ObjectId.Equals(userObjectID))
.ExecuteAsync();
IUser user = result.CurrentPage.ToList().First();
AD computes my query, sees that it only returns me, and deduces that I am allowed to view my own info. Execute succeeds, returning just me.
On a different page, I want to show the mail addresses used in the company (to tag a user, to typeahead, to check for existance, etc.) I try the following:
result = await activeDirectoryClient.Users
.ExecuteAsync();
return result.CurrentPage
.ToList();
This fails, "insufficient privileges". I am not allowed to view the entire User I guess. My delegated permissions are to "Read all users' basic profiles", meaning:
Allows the app to read the basic profile of all users in the
organization on behalf of the signed-in user. The following properties
comprise a user’s basic profile: display name, first and last name,
photo, and email address.
So, I try to filter:
result = await activeDirectoryClient.Users
.Where(u => u.Mail.StartsWith(str))
.ExecuteAsync();
return result.CurrentPage
.ToList();
but that still gives me the entire User, and I'm yet again hit with "insufficient privileges". So I try
result = await activeDirectoryClient.Users
.Where(u => u.Mail.StartsWith(str))
.Select (u => u.Mail)
.ExecuteAsync();
return result.CurrentPage
.ToList();
Which gives the cryptic runtime error (free translation from Dutch)
GenericArguments[1], System.String, Microsoft.Azure.ActiveDirectory.GraphClient.Extensions
.ReadOnlyQueryableSet.`2[TSource,TISource] conflicts with type TISource.
And I am at a loss. No source code seems to be available for ActiveDirectoryClient, and the usual Graph API doesn't even mention selecting only basic info.
The "easy" solution would be "just get more app permissions", but that needs a lot of time to go through the bureaucracy. And I SHOULD be able to get all Users' mail, right?
First and foremost, you don't need to do anything special to "Query only basic UserInfo from Azure AD with limited permissions". You just query Users, and it will initialize any fields you do not have access to as null. Insufficient privileges means you're not allowed to look at the user at all. Red flag.
At first I thought my tokencache was faulty. Which it was. Then I fixed it. Still errors.
By looking at several tokens in different applications with the online tool linked by Nan Yu I found out I was missing the actual permission to look at users' basic profiles in my token.
I still didn't get the permission in the token, and found out that even though the checkbox under "Delegated Permissions" was checked, the "Grant Permissions" option was not succesfully used afterwards.
PSA: don't assume all checked boxes are actually granted. Check in the App Service which permissions it has. If you're allowed that by your company, that is.
I'm writing a c# program right now that tries to authenticate with Azure to make a generic http request. I finally got the code working and I wanted to test the features but for every request I make I get the following error code in response:
{"error":{"code": "AuthorizationFailed", "message":"The client "(id of the app I registered in AzureAD)" with object id "(same value as before)" does not have authorization to perform action 'Microsoft.Authorization/roleAssignments/read' over scope '/subscriptions/(mysubscriptionid)'."}}.
The thing is ... The account I use to set everything up is a global admin. I checked every permission box in AzureAD I could find...
(that's 8 Application Permissions and 9 Delegated permissions in the Windows Azure Active Directory API and 1 delegated Permission in the Windows Azure Service Management API, though I don't know why there aren't more possible permissions for Azure Service Management)
the relevant code is rather basic but it works so I don't feel like I need post it, I'll just say that I obtain the Token using Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenAsync() with
authorityUri = "https://login.windows.net/(mytenantid)",
string resourceUri = "https://management.azure.com/";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
var res = authContext.AcquireTokenAsync(resourceUri, new
ClientCredential(clientId,clientSecret));
return res.Result;
and make the Request to
https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleAssignments?api-version=2016-03-01&$filter=atScope()
(as an example, this one is supposed to call the roles).
Tried several different types of GET Requests to different URIs, all give similar errors.
I'm thinking it might not be an issue with the code but a setting in the AzurePortal but everything I found there seems set up right (or rather "universal access").
According to your description, you forget to grant your service principal. You could add it on Azure Portal. You could grant Contributor or Owner role to it.
Please refer to this link:Assign application to role.
I'm trying to access the groups a user is a member of using the Microsoft Graph API.
I'm facing an issue because I think my permissions are set correctly, however, when I sign into the app, I get the message :
AADSTS90093: Calling principal cannot consent due to lack of permissions.
The weird thing is that I'm only asking for this permission scope :
public static String[] ClientScope = { "User.Read", "User.ReadBasic.All", "Group.Read.All"};
What makes me confused is that if I sign in the Microsoft Graph explorer and go to https://graph.microsoft.com/v1.0/me/memberOf ,
I get the correct results.
I got an admin to consent to the permissions I'm asking in the scope of course.
Has anyone encountered that issue ?
Any idea how I should correct that ?
The memberOf API requires one of the following scopes:
Directory.Read.All
Directory.ReadWrite.All
Directory.AccessAsUser.All
Regardless of which of these scopes you choose, they all will require administrative consent before a regular user can authorize them. To do this, you'll first need to have them go through the “Admin Consent” workflow. This workflow requires an administrator but once complete any users of your application will have “admin consent” to the restricted scope.
For example, you would normally you would then authenticate users by redirecting them to
https://login.microsoftonline.com/common/oauth2/authorize?<your params>.
Since this scope requires an Admin however, you fist need to obtain consent by first having an Admin authenticate by redirecting them to
https://login.microsoftonline.com/common/adminconsent?<yours params>.
Once an Admin grants consent, normal users will be able to use OAUTH to authenticate.
I have been told to raise a question about Azure AD Graph Api here instead of raising it as an issue for the corresponding GitHub sample repository, I hope Azure Graph API team monitors SO and can help us with this github sample issue
Some extra context for the problem:
We are using Microsoft.Azure.ActiveDirectory.GraphClient nuget to create and manage users in our Azure AD test tenant. Following this sample application
we can create and update users in Azure AD via Graph API. That was fine until some moment which happened about 2-3 days ago (not sure about the exact moment, we discovered the problem on Tuesday morning AU time. Last successful run was on Friday last week). It was 100% working code and to confirm that it's not our code - I ran through sample application again - it's broken now too. I've tested it with the latest GraphClient v2.1.0 and original one from sample app which is - v2.0.6
To simplify testing of the problem I've made a LINQ based sample with some secrets redacted ( you need to follow console app sample guide to put in your values if you want to run it, instead of original sample app)
Also here is the Fiddle captures (redacted) of
Authentication request-response (client-request-id: 88b2bbbd-94cd-498d-a147-caad05e16eb7)
User Creation failing Attempt
Few things to note in the fiddler captures - Azure AD Graph API doesn't return refresh token along with access token:
{"expires_in":"3599","token_type":"Bearer","scope":"UserProfile.Read",
"expires_on":"1441183928","not_before":"1441180028","resource":"https://graph.windows.net",
"access_token":"TOKEN WAS HERE"}
I can see the issue with the scope string here, but we are not setting any explict scope in GraphClient when calling for token as per Sample app ( and this code was fine before, as I mentioned early)
User creation response is clear in terms of what happens and why it happens
{"odata.error":
{"code":"Authorization_RequestDenied","message":
{"lang":"en","value":"Insufficient privileges to complete the operation."}
}
}
But it's not clear how to ask for extra permission scopes through any of these AuthenticationContext.AcquireToken Method overloads
Also it's strange that the very same code was fully functional before and is broken now, after some mysterious change?
So I have few questions:
How to add extra scope permissions in GraphClient library to get Graph API token with User Modification enabled. This is probably a band aid fix of the problem.
It looks like Azure AD tries to manage permissions for client apps in the portal. But there is no extra permissions for Native Client type of application. How can I explicitly update app permissions so the existing code can work again. Is it possible at all ?
Can anyone recommend other libraries to interact with GraphAPI, which allow the consumer to explicitly specify scope for the requested token ?
================Update================
Yes, I saw that consent flow documentation. Chasing the issue I've created new Azure AD tenant, added brand new application and added all possible rights, including all available application and delegation ones:
now it looks like this. I also
I can get a token with long list of scopes, e.g.
Directory.AccessAsUser.All
Directory.Read
Directory.Write
User.Read
User.ReadWrite
User.Read.All
User.ReadBasic.All
User.ReadWrite.All
user_impersonation
UserProfile.Read
--cut unrelated scopes--
But it still gives me 403 :
{"odata.error":
{"code":"Authorization_RequestDenied","message":
{"lang":"en","value":"Insufficient privileges to complete the operation."}
}
}
One thing worth to note - in the scope list there is no Directory.ReadWrite.All
But here docs says :
Directory.ReadWrite.All : Read and write directory data
================Update================
PS: Some technical request info for Azure AD engineers:
Authentication request-response has client-request-id: 88b2bbbd-94cd-498d-a147-caad05e16eb7.
Failed Graph call has client-request-id: 882f3918-0ddd-40fe-a558-866997e32b46 in response only
The issue here is that you have not properly configured your application to request the correct permissions to the Graph API.
To do this, you must go into the Azure Management Portal and configure your 'permissions to other applications' to include the scopes your app needs to be able to read/write to the directory.
We have some documentation here which should help you:
https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx (Describes the consent flow)
https://msdn.microsoft.com/Library/Azure/Ad/Graph/api/graph-api-permission-scopes (describes the specific permissions that the graph API exposes that your application will need to request)
I hope this helps!