I'm trying to read all users from my Azure AD with Graph with the following method:
public void GetUsers() {
var confidentialClient = ConfidentialClientApplicationBuilder
.Create("my application id")
.WithTenantId("my tenant id")
.WithClientSecret("my application secret")
.Build();
var graphClient = new GraphServiceClient("https://graph.microsoft.com/beta", new ClientCredentialProvider(confidentialClient));
var request = graphClient.Users.Request().Filter("accountEnabled eq true");
var users = await request.GetAsync(); // throws exception!
}
When I execute request.GetAsync() I receive the following exception:
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"date": "2021-08-26T14:25:27",
"request-id": "d2772ea1-a994-4f14-bfad-0baffc6d24d3",
"client-request-id": "my application id"
}
}
}
On Azure AD I created an application, and I added over "API permissions" these permissions Read.User.All and Read.User
Do I need another specific permission? It's coding error?
Please make sure permission type is "Application" and not "Delegated" and Status shows "Granted for "
If you see status as "Not granted" , click on "Grant admin consent"
Related
We are currently trying to create a tool in Google Apps Script using OAuth2 for Authentication. The script is supposed to use the GMail api to carry out some tasks such as moving labels from one account to another.
Documentation we have used says we need to create a service account with domain wide authority and create necessary components to allow it to work (i.e client_id and so on.. )
We are getting the error below is anyone able to help?
Code:
function getGmailService() {
return OAuth2.createService('GmailMigration:' + user_email)
// Set the endpoint URL.
.setTokenUrl('https://oauth2.googleapis.com/token')
.setAuthorizationBaseUrl(CREDENTIALS.auth_uri)
// Set the private key and issuer.
.setPrivateKey(CREDENTIALS.private_key)
.setIssuer(CREDENTIALS.client_email)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(CLIENT_EMAIL)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope('https://mail.google.com https://www.googleapis.com/auth/gmail.modify
https://www.googleapis.com/auth/gmail.labels https://www.googleapis.com/auth/gmail.insert
https://www.googleapis.com/auth/gmail.addons.current.message.action https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.addons.current.message.metadata https://www.googleapis.com/auth/gmail.metadata');
}
function reset() {
getGmailService().reset();
}
function run() {
var service = getGmailService();
if (service.hasAccess()) {
console.log({Service: service})
var url = 'https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{message/label_id}?key='+CREDENTIALS.api_key;
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
},
muteHttpExceptions: true
});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));} else {
Logger.log(service.getLastError());
}
}
Error:
{
"error": {
"code": 400,
"message": "Precondition check failed.",
"errors": [
{
"message": "Precondition check failed.",
"domain": "global",
"reason": "failedPrecondition"
}
],
"status": "FAILED_PRECONDITION"
}
}
Thanks
I want to validate user credential from Azure AD. It works for users who haven't enable MFA.but MFA enabled users getting below error.
Due to a configuration change made by your administrator, or because
you moved to a new location, you must use multi-factor authentication
to access
So it need a way to ignore MFA ,when we accessing though the graph API
this is my code.
var values = new Dictionary<string, string>
{
{ "grant_type", "password" },
{ "client_secret", appKey },
{ "client_id", clientId },
{ "username", userName },
{ "password", password },
{ "scope", "User.Read openid profile offline_access" },
};
HttpClient client = new HttpClient();
string requestUrl = $"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token";
var content = new FormUrlEncodedContent(values);
var response = client.PostAsync(requestUrl, content).Result;
if (response.IsSuccessStatusCode)
{
return true;
}
else
{
return false;
}
The correct way to validate user credentials is have the user authenticate interactively through a browser.
This will allow them to go through MFA, login through federation with ADFS etc.
And most importantly, the users do not have to give their password to your app.
The flow you are trying to use only exists in the spec as an upgrade path for legacy applications.
Its usage becomes essentially impossible once MFA is enabled.
I'm having trouble creating a user in an Azure Active Directory with a custom identity. The body of my request looks like this:
{
"passwordProfile": {
"password": "password-value"
},
"accountEnabled": true,
"displayName": "FIRSTNAME LASTNAME",
"passwordPolicies": "DisablePasswordExpiration",
"creationType": "LocalAccount",
"identities": [
{
"issuerAssignedId": "avalid#email.com",
"signInType": "emailAddress",
"issuer": "my_tenant.onmicrosoft.com"
}
]
}
I've also tried a version of the request where I specify mailNickname and userPrincipalName. In every case, the creation fails with the error:
{
"error": {
"innerError": {
"date": "2020-02-20T17:23:48",
"request-id": "c5a7c8da-35bd-4ae2-9ae8-6714b672f035"
},
"message": "One or more properties contains invalid values.",
"code": "Request_BadRequest"
}
}
There's a code snippet in the C# docs that suggests this should be possible.
What am I missing?
Microsoft Graph allows you to manage user accounts in your Azure AD B2C directory by providing create, read, update, and delete methods in the Microsoft Graph API. You can migrate an existing user store to an Azure AD B2C tenant and perform other user account management operations by calling the Microsoft Graph API.
If you try to use this Azure AD Graph API request for a normal Azure AD tenant, it will get the same error massage as yours.
So, ensure the tenant you're trying to query is a B2C tenant.
Try to use the global admin of the B2C tenant (e.g. username#b2ctenant.onmicrosoft.com) to obtain a token. Then use the token in the head to use the API :
Request:
POST https://graph.windows.net/myorganization/users?api-version=1.6
Body Content-Type: application/json:
{
"passwordProfile": {
"password": "password-value"
},
"accountEnabled": true,
"displayName": "FIRSTNAME LASTNAME",
"mailNickname": "mspcai",
"passwordPolicies": "DisablePasswordExpiration",
"creationType": "LocalAccount",
"identities": [
{
"issuerAssignedId": "avalid#email.com",
"signInType": "emailAddress",
"issuer": "my_tenant.onmicrosoft.com"
}
]
}
Looks like you are referring to a beta snippet, please try the following endpoint:
https://graph.microsoft.com/beta/users
I need some help for access tokens in GCP. I am using Java as program language and I tried different approaches like:
https://cloud.google.com/iap/docs/authentication-howto
and https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth
I am using the second approach. Code snippet:
String privateKeyId = "my-private-key";
long now = System.currentTimeMillis();
String signedJwt = null;
try {
Algorithm algorithm = Algorithm.RSA256(null, privateKey);
signedJwt = JWT.create()
.withKeyId(privateKeyId)
.withIssuer("my-issuer")
.withSubject("my-subject")
.withAudience("https://www.googleapis.com/compute/v1/compute.machineTypes.list")
.withIssuedAt(new Date(now))
.withExpiresAt(new Date(now + 3600 * 1000L))
.sign(algorithm);
} catch (Exception e){
e.printStackTrace();
}
return signedJwt;
Then I perform get instances setting the returned token as Bearer authorization header but response is:
com.google.api.client.http.HttpResponseException: 401 Unauthorized
{
"error": {
"errors": [
{
"domain": "global",
"reason": "authError",
"message": "Invalid Credentials",
"locationType": "header",
"location": "Authorization"
}
],
"code": 401,
"message": "Invalid Credentials"
}
}
With same credentials I am able to access the SDK.
Thanks!
As per #DalmTo, you should be using the client library for Java. This is the link to get you started.
Scenario is Angularjs 1.6.5 app with a c# WebApi. Authentication is done against AAD with the use of angular-adal.js. Up to now, everything Works perfectly, as users are able to login through AAD and WebApi accepts the token.
For this specific app, the roles are in an External application, to which the WebApi has Access. I have been able to add the role claims (after fetching them from the External app) with the use of WindowsAzureActiveDirectoryBearerAuthenticationOptions with the following code inside the ConfigureOAuth(IAppBuilder app):
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudience = clientId
},
//Audience = ConfigurationManager.AppSettings["ida:ClientID"],
Tenant = tenant,
Provider = new OAuthBearerAuthenticationProvider
{
OnValidateIdentity = async context =>
{
// Retrieve user JWT token from request.
var authorizationHeader = context.Request.Headers["Authorization"];
var userJwtToken = authorizationHeader.Substring("Bearer ".Length).Trim();
// Get current user identity from authentication ticket.
var authenticationTicket = context.Ticket;
var identity = authenticationTicket.Identity;
if (identity.FindFirst(System.Security.Claims.ClaimTypes.Role) == null)
{
var user = identity.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn").Value;
Cis.bll.Xrm.bllSystemUserRoles bllSystemUserRoles = new Cis.bll.Xrm.bllSystemUserRoles();
var su = bllSystemUserRoles.getByEmail(user);
//var roleClaim = new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, su.stringRoles);
foreach (var item in su.Roles)
{
identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, item.xrmName));
}
}
}
}
});
So for each httpRequest that Angularjs does to the API, the previous function looks up the roles for the user and adds the role claims. With this implementation, I am able to use an AuthorizeAttribute in the Controller methods, restricting Access to only certain roles like so:
[CustomAuthorize(Constants.Roles.resourcesAdministrator)]
I find this way highly inneficient, because with each httpRequest, the API has to fetch the roles of the user from the database (or whatever persistance way is implemented).
What I want to do is to read the user roles just once, and then be able to use them in the API with every subsequent request. Is there a way to add the claims to the token AFTER we recieve the token for AAD?
BTW, I could just add a Roles property to each model, or something like that, but it is not what I'm looking for.
If you have any other ideas or suggestions, they will be greatly appreciated.
Regards
The token is not able to modified since it is issued. And since the roles is stored in the other application, I don't think it is possible to get the roles without query the database.
In this scenario, we can manage the roles though the Azure AD application roles & role claims. Then it will issue the roles claim in the id_token.
For example, we can modify the manifest of the app like below:
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Writer",
"id": "d1c2ade8-98f8-45fd-aa4a-6d06b947c66f",
"isEnabled": true,
"description": "Writers Have the ability to create tasks.",
"value": "Writer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Observer",
"id": "fcac0bdb-e45d-4cfc-9733-fbea156da358",
"isEnabled": true,
"description": "Observers only have the ability to view tasks and their statuses.",
"value": "Observer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "fc803414-3c61-4ebc-a5e5-cd1675c14bbb",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "Approver"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Admin",
"id": "81e10148-16a8-432a-b86d-ef620c3e48ef",
"isEnabled": true,
"description": "Admins can manage roles and perform all task actions.",
"value": "Admin"
}
],
And assign the roles to the user through the application via Azure portal like figure below:
Then we can get the id_token like request below(implicit grant flow), the roles should be in the token. And we can call the web API using this token.
Get:https://login.microsoftonline.com/{tenant}/oauth2/authorize?response_type=id_token&client_id={clientId}&redirect_uri={redirect_uri}&nonce={nonce}
id_token sample: