Create a user passing in a json of user object (Microsoft Graph) - c#

I'm trying to create a user by calling microsoft graph and passing in a json string (one that looks like a user object) into the req.body of a httprequest.
The steps I am currently following are:
Call microsoft graph to get the user's properties
Serialize content into a json string (jsonString) and pass it in as the req.Body of a HTTPRequest when using a graph call to create a user in azure active directory
When I pass the content into the req.Body, since there are required fields that must be filled out (accountEnabled, displayName, onPremisesImmutableId, password, etc.), it will not be created cause it does not specify the required field (ex: In the content of jsonString, password is set to null. Password would need to have a value).
The source link of the graph call is found here: https://learn.microsoft.com/en-us/graph/api/user-post-users?view=graph-rest-1.0&tabs=http
Is there a way to pass in my jsonString and also specify some of the user properties within the req.Body? If not, is there a workaround?
var createUser = await httpClient.PostAsync(link, "Token", jsonString);

It's important that you cannot retrieve the password for any user in Azure AD in any way.
So, you need to set the value of the password in your code.
The other properties(displayName, MailNickname, UserPrincipalName, etc.) could be set directly, seeļ¼š
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
User user = await graphClient.Users["{user-id}"].Request().GetAsync();
var newUser = new User
{
AccountEnabled = true,
DisplayName = user.DisplayName,
MailNickname = user.MailNickname,
UserPrincipalName = user.UserPrincipalName,
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "password-value"
}
};
await graphClient.Users.Request().AddAsync(newUser);
I refer to the code with C# in the link.

Related

Generate user token from AuthenticationContext

I am trying to generate a user token for the purpose of testing an API that requires one. The tests run automatically. I have the following code example, but it seems to be out of date
Uri endpointUri = new Uri("my endpoint");
string resource = "my rid";
string clientId = "my client id";
PlatformParameters parameters = new PlatformParameters(PromptBehavior.Auto);
string authContextURL = "my url";
var authenticationContext = new AuthenticationContext(authContextURL, new TokenCache());
// Here you are sending a request to AAD with the user credentials.
AuthenticationResult result = await authenticationContext.AcquireTokenAsync(resource: resource, clientId: clientId, redirectUri: endpointUri, parameters);
// If the request succeeded you can get the user access token as follows.
return result.AccessToken;
The reason I believe it to be out of date is that PlatformParameters now requires 2 parameters, and I cannot find what the 2nd parameter should be by default.
My question is, how can I create a user-context token to use in testing my API from the test code?
EDIT
According to this answer, PlatformParameters with 1 param is for .netframework, whereas I am using .net 6
Still looking to any leads there may be!

Create a user passing in a user object (Microsoft Graph)

I'm trying to create a user using a microsoft graph call using this link: https://learn.microsoft.com/en-us/graph/api/user-post-users?view=graph-rest-1.0&tabs=csharp
However, is there a way to create a user by passing in a User object or a json representation of a user object in an azure function as a parameter As shown below?
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "user/settings")] HttpRequest req, ILogger logger, User user)
Also, is there a way to read the whole req.Body (w/ additional properties) and create a user, instead of only applying the required parameters (shown below)? Each and every user will have different properties
{
AccountEnabled = true,
DisplayName = "displayName-value",
MailNickname = "mailNickname-value",
UserPrincipalName = "upn-value#tenant-value.onmicrosoft.com",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "password-value"
}
};
await graphClient.Users
.Request()
.AddAsync(user);
For your first question, I don't think we can pass a User object to function directly to create the user. But we can pass all of the properties into the function to create it. As your second question mentioned, it is not easy for us to create the user if every user has different properties. So we can pass all of the properties as json into function and then read the json from the req and concat these properties as json string. After that, do not use graph sdk to create user. Do a post request with graph api by ourself like below code:
string str = "{\"displayName":\"xxxx\",\"mailNickname\":\"xxxx\"}";
var content = new StringContent(str, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "your token");
var response = client.PostAsync("https://graph.microsoft.com/v1.0/users", content).Result;

Microsoft Graph API - user extension data in C#

I have an Azure AD B2C directory with some users in it. I have been using the Microsoft Graph API and through both https://developer.microsoft.com/en-us/graph/graph-explorer and PostMan I have been able to create and modify users along with including an extension attribute (eg: extension_[guid in our tenant]_ContactMethod) - details passed in json in the body of the request in PostMan.
That is fine, however I need to be albe to do the same in C#. I can successfully create the user without specifying any extensions:
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var user = new User
{
AccountEnabled = true,
DisplayName = "John Smith",
MailNickname = "JohnSimth",
UserPrincipalName = "JohnSmith#[tenant].onmicrosoft.com",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "[Randomly Generated Password]"
}
//[Extension attributes to add here]
};
await graphClient.Users.Request().AddAsync(user);
However I need to be able to specify some extension attributes when creating / modifying the user in C#. How do I do this?
You cannot directly add extensions at the time of creation according to this limitations document.
After creating the user, you need to create a separate request that hits the extensions endpoint as shown in the below code and this adds these extension details to the user.
var extension = new OpenTypeExtension
{
ExtensionName = "{ExtensionName}",
AdditionalData = new Dictionary<string, object>
{
{"FirstEmail", "abc#yahoo.com"},
{"SecondEmail" , "xyz#yahoo.com"}
}
};
await graphClient.Users["{UserId}"].Extensions
.Request()
.AddAsync(extension);
So just after user creation, get that userid and use it to hit extensions endpoint as shown in the above code.

How to force change password after first login

I have a Azure Active Directory B2C tenant. I also have a small service that creates new users in the B2C tenant from a different system. This way I can synchornize both systems. When a user has been added to B2C and logs in the first time, I want the user to be forced to change the password. But whatever I do, the user can just log in and continue, without changing the password..
To add a user to B2C, I use the Microsoft Graph 1.14 package. I push the user information as JSON to the endpoint https://graph.windows.net/{tenantId}/users?api-version=1.6
The log in page is an Azure custom page in the user flow policies. There is also a change password policy, if needed.
This I tried:
When adding the user, I set the password profile. Adding the property "ForceChangePasswordNextLogin" and setting it to true, does not work.
Someone suggested to add the "ForceChangePasswordNextSignIn" property, but B2C doesn't know this property.
Tried to fix it in the policy; didn't work.
Used Google and StackOverflow; not much luck.
This is the user I post to Microsoft Graph:
var user = new GraphUserModel
{
City = "Amsterdam",
CustomField= "999999",
Department = "TestPassword",
DisplayName = "TestPassword",
OtherMails = new[] { "myemail#something.nl" },
PostalCode = "1234 AB",
StreetAddress = "Hoofdweg 6",
Surname = "TestPassword",
TelephoneNumber = "0123456789",
ChainCode = null,
MailNickname = "999999",
UserPrincipalName = "999999#{tenantNameHere}",
SignInNames = new List<SignInNames>
{
new SignInNames
{
Type = "userName",
Value = "999999"
}
},
AccountEnabled = true,
CreationType = "LocalAccount",
PasswordProfile = new PasswordProfile
{
Password = "SomeRandomPassword"
},
PasswordPolicies = "DisablePasswordExpiration"
};
The users are created correctly, but when they log in for the first time, I would like to see a page where they are forced to change the password.
With Sign-up/Sign-in policy I had to implement that manually by flagging users in DB if they have changed the password and then redirecting to password change if they have not changed the password.
I was also not able to find 'out of the box' solution. I found that forceChangePasswordNextLogin works only with Sign-in policy.

ASP.NET Identity, Register manual added user without deleting him

I have an issue with ASP.NET Identity. In my application, I want to add users to the table dbo.AspNetUsers, as soon as someone adds them to a poll with their mail adress, like this:
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
TwoFactorEnabled = false,
EmailConfirmed = false,
Registered = true
};
_dbContext.ApplicationUsers.Add(user);
_dbContext.SaveChanges();
If someone who was added like this to the database earlier, wants to register himself with his mailadress, I don't want to delete the manually added user and register him as a new one, because other relations are already related to his ID and constraints would not allow that. I also can not delete the connected relations, because other users are also related to them.
I tried to manually add a hashedPassword to him in the database like this:
_dbContext.ApplicationUsers.FirstOrDefault(u => u.Email == model.Email).PasswordHash =
this.HashPassword(user, model.Password);
_dbContext.SaveChanges();
But then the login failed, because of an internal server error, because of a NULL value in
"System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue)".
Does someone know a solution to register a user, who was already added manually, without deleting him?
Thanks for answers!
EDIT/SOLUTION
Here is the solution:
In a first step, just create the user with a default password, then if he wants to register, remove the Password and add the Password from the RegisterModel, like this:
var result = await _userManager.CreateAsync(user, "DefaultPassword1.");
await _userManager.RemovePasswordAsync(user);
var result = await _userManager.AddPasswordAsync(user, model.Password);
If you look in the Manage Controller you'll see all the methods to manage user accounts. For example to add a password you'd use
var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);

Categories

Resources