What is the best way to update a department name in Active Directory and Azure for 100+ users? - azure-active-directory

Azure is currently setup to sync from on
prem. Active Directory. What is the best way to update the department name
in Active Directory and Azure for these users? Below is a sample of the list.
Name
Old Department Name
New Department Name
Larry Lue
Collections
Collector Members
Erica Anderson
Collections
Collector Members
Mary Lee
Collections
Collector Members

You can use ms graph api to do the update by code. But this api doesn't provide a batch operation, so you have to update user profile one by one. Here's my test result:
Before updating the department, the original department look like this:
After update it by code. it will be changed to the new value.
Here's the code snippet:
using Microsoft.Graph;
using Azure.Identity;
public async Task<IActionResult> IndexAsync()
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "azure_ad_app_id";
var clientSecret = "azure_ad_app_client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
//query user information
var user = await graphClient.Users["user_id"]
.Request().Select("displayname, department").GetAsync();
//update user information
var userDept = new User
{
Department = "Collector Members"
};
await graphClient.Users["9a8ae89f-711a-434a-8d08-43e1f7d29af2"]
.Request()
.UpdateAsync(userDept);
}

Related

Azure AD/Office 365: Create similar groups for two different domains

I have two domains registered in Azure AD, domainA.com and domainB.com, and I want to create two similar Groups for them:
support#domainA.com
support#domainB.com
How can I do that?
Im trying code like below via Microsoft Graph, and first Group is created successfully. However there is an error when adding the second group for domain B:
"Another object with the same value for property mailNickname already
exists"
public async Task CreateSupportGroups()
{
// Create the group for domain A
await UpdateDefaultDomain("domainA.com");
await AddNewGroup("Support group for Domain A");
// Create the group for domain B
await UpdateDefaultDomain("domainB.com");
await AddNewGroup("Support group for Domain B");
}
public async Task AddNewGroup(String groupName)
{
var group = new Group
{
Description = "Testgroup",
DisplayName = groupName,
GroupTypes = new List<String>()
{
"Unified"
},
MailEnabled = true,
MailNickname = "support",
SecurityEnabled = false,
Visibility = "Private"
};
await graphClient.Groups
.Request()
.AddAsync(group);
}
public async Task UpdateDefaultDomain(String domainID)
{
var domain = new Domain
{
IsDefault = true
};
await graphClient.Domains[domainID]
.Request()
.UpdateAsync(domain);
}
I have tested in my environment.
Please make domainA.com as primary and create a group with displayname support A and mailnickname as support
Then make domainB.com as primary and create a group with displayname support B and mailnickname as supportB because if you create with mailnickname as support, it will throw below error :
After creation of Support B Group, edit the primary mail of the group to support#domainB.com. Even though it throws error, the primary mail of the group is updated.
Please refer below screenshot :

How To Update MS Graph Client Service Principal AppRoleAssignments

I am attempting to update a user's AppRole assignments via the Graph Client. As per MS documents I am attempting to do it from the service principal side rather than the user side.
var sp = await _graphServiceClient.ServicePrincipals[objectId].Request().GetAsync();
ServicePrincipal newSp = new ServicePrincipal
{
Id = objectId,
AppId = _configuration["AzureAd:AppId"]
};
newSp.AppRoleAssignedTo = new ServicePrincipalAppRoleAssignedToCollectionPage();
newSp.AppRoleAssignedTo.Add(new AppRoleAssignment
{
PrincipalId = new Guid(u.Id),
ResourceId = new Guid(objectId),
AppRoleId = new Guid(r)
});
await _graphServiceClient.ServicePrincipals[objectId].Request().UpdateAsync(newSp);
I am getting 'One or more property values specified are invalid' but of course no real info on what property or even which object is the problem.
Anyone see anything obvious? I'm guessing on the syntax for the client usage bc I don't see much documentation or examples for it.
I test with same code with yours and met same issue and do some modification but still can't solve the issue. For your requirement of update user's AppRole assignment, I'm not sure if we can do it by the code you provided, but I can provide another solution which is more directly.
The code you provided is new a service principal and add the role assignment into it, then update the service principal. Here provide another solution, it can add the app role assignment directly:
var appRoleAssignment = new AppRoleAssignment
{
PrincipalId = Guid.Parse("{principalId}"),
ResourceId = Guid.Parse("{resourceId}"),
AppRoleId = Guid.Parse("{appRoleId}")
};
await graphClient.Users["{userId}"].AppRoleAssignments
.Request()
.AddAsync(appRoleAssignment);
The code above request this graph api in backend.

Blazor WASM - Identity RoleClaims

In my previous MVC projects, I was using default identity pages to login (/Identity/Account/Login)
By using the code below on my Controller.cs, I can get various values like the roles that current user is assigned to, the claims of the roles, etc...
var claims = User.Claims; // or HttpContext.User.Claims
//expected claim values are:
//{the-user-guid}
//email#test.com
//["Admin", "Manager"]
//Permission.Module1.Create <-- I need this (in Blazor)
//Permission.Module2.Read <-- I need this (in Blazor)
//and so on...
However, having the same setup with Blazor, calling User.Claims doesn't include the roles and the claims of the roles by default.
I was able to include the roles (ie. Admin, Manager) that user is assigned to by doing this. So the next bit I am aiming to achieve is getting the RoleClaims (from AspNetRoleClaims table) - which would give me the Permissions.
In the context of the solution from the link, I am not sure if there are other "keywords" I can use (apart from "role") to be able to get the RoleClaims. I would also appreciate it if you could point me to a resource with the list of these keywords.
You will need to inject The following provider in your page
#inject Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider AuthenticationStateProvider
Then use it as following
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
user = authState.User;
var claims = user.Claims?.ToList();
Also if you want to secure your pages based on Roles/policy
you could add the policy in program.cs
as following
builder.Services.AddAuthorizationCore(options =>
{
options.AddPolicy("Admin", policy =>
{
policy.RequireAuthenticatedUser();
policy.RequireRole("Admin");
});
});
Then use it within your partial class as following
[Authorize(Policy = "Admin")]
or within your page as following
#using Microsoft.AspNetCore.Authorization
#attribute [Authorize(Policy ="Admin")]
Good luck
Edit April 28, 2021
Thanks for the Update Majo
If you want to get the user information within the controller
you will need to inject the UserManager in your controller constructor
private readonly ILogger<WeatherForecastController> _logger;
private readonly UserManager<ApplicationUser> userManager;
public WeatherForecastController(ILogger<WeatherForecastController> logger ,
UserManager<ApplicationUser> userManager)
{
_logger = logger;
this.userManager = userManager;
}
Then inside your action you will be able to get all the claims and rols as desired using the instance of UserManager
within your action you could use something like this
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); // get the user ID
var user = await userManager.FindByIdAsync(userId); // get the user object
var claims = await userManager.GetClaimsAsync(user); // get the claims based on the user object
var rols = await userManager.GetRolesAsync(user); // get the roles based on the user object
I hope this answer your question!
Regards,
Khaled Dehia

How to retrieve the userid from userprincipalname in azure active directory?

My client has synchronization set up between an on-premises Active Directory (AD) and Azure Active Directory (AAD).
I am able to retrieve user information from AAD using Microsoft Graph without a problem but, I specifically need to get the AD UserID, ie ({domain}/{userid}).
I tried calling https://graph.microsoft.com/v1.0/users/firstname.lastname#domain.com/$select=userId but it did not work.
My questions are, is it possible? And in that case what is the actual attribute name? I have been looking around but haven´t been able to find a complete list of attributes.
EDIT:
After receiving one answer from Marilee I am including the C# code I have been using, ish. Both the calls do work for receiving user information from AAD, but not the AD UserID, ie ({domain}/{userid}) that I am looking for.
Attempt no 1
var requestUri = GraphBaseUri + $"/v1.0/users/{upn}?$select=userId";
var response = await _httpClient.GetAsync(new AuthenticationHeaderValue("Bearer", accessToken), requestUri).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
dynamic responseObj = JsonConvert.DeserializeObject(content) as JObject;
return responseObj.UserId; //NOT WORKING
Attempt no 2
var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) => {
requestMessage
.Headers
.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
return Task.FromResult(0);
}));
// Retrieve a user by userPrincipalName
var user = await graphClient
.Users[upn]
.Request()
.GetAsync();
return user.ObjectId; //NOT WORKING
The attribute you're referring to is the objectID. From Graph API you can use UPN like you said:
GET /users/{id | userPrincipalName}
You can look up the user in a few different ways. From the /users endpoint you can either use their id (the GUID assigned to each account) or their userPrincipalName (their email alias for the default domain):
// Retrieve a user by id
var user = await graphClient
.Users["00000000-0000-0000-0000-000000000000"]
.Request()
.GetAsync();
// Retrieve a user by userPrincipalName
var user = await graphClient
.Users["user#tenant.onmicrosoft.com"]
.Request()
.GetAsync();
If you're using either the Authorization Code or Implicit OAuth grants, you can also look up the user who authenticated via the /me endpoint:
var user = await graphClient
.Me
.Request()
.GetAsync();
From Powershell you can query Object IDs:
$(Get-AzureADUser -Filter "UserPrincipalName eq 'myuser#consoso.com'").ObjectId
The way to do this is;
var requestUri = GraphBaseUri + $"/v1.0/users/{upn}?$select=onPremisesSamAccountName";
var response = await _httpClient.GetAsync(new AuthenticationHeaderValue("Bearer", accessToken), requestUri).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<ResponseObj>(content);
return responseObj.OnPremisesSamAccountName;
Notice the select where we collect the onPremisesSamAccountName. Though, I haven´t found a comprehensive list of all attributes possible to retrieve which would have been nice.

Azure Graph service not finding newly created user

I have a web application that uses Azure ACS and Azure AD to handle our authentication.
We have a user management feature in the web application that allows a user to create new users. This takes the details such as username, password, email etc. and uses the graph service to create a user in azure.
var newUser = new Microsoft.WindowsAzure.ActiveDirectory.User
{
userPrincipalName = user.UserName,
mailNickname = user.MailNickname,
accountEnabled = true,
displayName = user.FirstName + " " + user.Surname,
givenName = user.FirstName,
surname = user.Surname
};
newUser.passwordProfile = new PasswordProfile
{
forceChangePasswordNextLogin = false,
password = user.Password
};
var graphService = GetGraphService(tenantName);
graphService.AddTousers(newUser);
graphService.SaveChanges();
We are then required to create a record in the web application database for this user. The record needs the object ID from azure. So we use the graphService to get the newly-created user details. This is where my problem lies. It doesn't find the user.
private string GetObjectIdFromAzure(string userName, string tenantName)
{
var graphService = GetGraphService(tenantName);
var users = graphService.users;
QueryOperationResponse<Microsoft.WindowsAzure.ActiveDirectory.User> response;
response = users.Execute() as QueryOperationResponse<Microsoft.WindowsAzure.ActiveDirectory.User>;
var user = response.FirstOrDefault(x => x.userPrincipalName == userName);
return user != null ? user.objectId : "";
}
My code was working without any issues for a few months and only today I am having issues. What frustrates me more it that I have another deployment of the same code where it works without any issues. Some differences between the two deployments are:
The deployments use different Access control namespaces in Azure
The deployments have separate applications in Azure AD
One is https, one is http
The users for both system are under the same Directory.
I have put in logging in both deployments to get the number of users returned by
users.Execute()
In both systems it reported 100 (they share the same users)
Any ideas of what would cause this to stop working? I didn't change any code relating to this recently, I haven't changed any configuration on Azure and I didn't change the web.config of the application
The problem was caused by the fact that I was filtering the users after retrieving them. The graph API was only returning a maximum of 100 users.
So the process was like so:
User created in Azure
Success message returned
Web App searches Azure for user to get Object ID
Graph Api only returns top 100 users. User was not in top 100 alphabetically so error thrown
The reason it was working on our second deployment was that I was prefixing the user name with demo_ (we use this site to demo new features before releasing). This meant that it was being returned in the top 100 users.
I changed the code as follows so it filters during the retrieval instead of after:
private Microsoft.WindowsAzure.ActiveDirectory.User GetUserFromAzure(string userName, string tenantName, out DirectoryDataService graphService)
{
graphService = GetGraphService(tenantName);
var users = (DataServiceQuery<Microsoft.WindowsAzure.ActiveDirectory.User>)graphService.users.Where(x => x.userPrincipalName == userName);
QueryOperationResponse<Microsoft.WindowsAzure.ActiveDirectory.User> response;
response = users.Execute() as QueryOperationResponse<Microsoft.WindowsAzure.ActiveDirectory.User>;
var user = response.FirstOrDefault();
return user;
}

Resources