Reputation: 11
We are using GRAPH SDK to manage users In Azure AD B2C. We have been able to create an user account and now want to assign a role to the user. We have referred the documentation but not able to find the way forward. Is there a way we can assign role to a user using Graph SDK
Any help on this would be appreciated
Upvotes: 1
Views: 1332
Reputation: 414
Azure AD B2C does not really support roles out of the box sadly. There are a couple of ways to do this. If you want to add the roles to your token on sign-in, then you will have to use custom policies and an API call (or Azure Function) to add roles to your claims. If you are new to custom policies, I highly recommend reading the official documentation on custom policies first.
If you only want to manage roles without adding them to your token on sign-in. You can create Security groups in your ActiveDirectory (In the same directory as your B2C tenant). This should look something like this.
You can then use the Get Groups call. or list memberOf call.
GET /groups/{id}
GET /me/memberOf
GET /users/{id | userPrincipalName}/memberOf
Ofcourse you can also add users to the groups
POST /groups/{group-id}/members/$ref
If you do want to add the roles to your token on sign-in, I personally used the video. https://www.youtube.com/watch?v=C9qN6QqnxQ8 This uses an Azure function but you can also use your own API if you want to.
IMPORTANT: You cannot test calls to your own API with localhost in custom policies, so make sure to make it available with something like ngrok.
I will describe the steps as well: First add the role (or roles) ClaimTypeReferenceId to your SignUp.xml
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" />
Other claims
<OutputClaim ClaimTypeReferenceId="role" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
In the TrustFrameworkExtensions.xml add the claimtype role (or roles)
<ClaimType Id="role">
<DisplayName>Role</DisplayName>
<DataType>stringCollection</DataType> <!-- or string if you only want 1 role -->
</ClaimType>
Add the Rest API call to your TrustFrameworkExtensions.xml. This sets the Parameters of your API call to an email address which you have received from the sign-in, and it expects a role as a result.
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-GetProfile">
<DisplayName>Get user extended profile Azure Function web hook</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<!-- Set the ServiceUrl with your own REST API endpoint -->
<Item Key="ServiceUrl">https://functions.azurewebsites.net/api/HttpTriggerGetRoles?code=YOURCODE</Item> <!-- TODO CHANGE THIS URL to your own-->
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">None</Item>
<!-- REMOVE the following line in production environments -->
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="emails" />
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
</InputClaims>
<OutputClaims>
<!-- Claims parsed from your REST API -->
<OutputClaim ClaimTypeReferenceId="role" PartnerClaimType="role"/>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
Lastly, add the GetRoleData TechnicalProfile to your second to last OrchestrationStep
<OrchestrationStep Order="10" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="GetRoleData" TechnicalProfileReferenceId="REST-GetProfile" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="11" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
For testing I created an Azure Function with the following code in C#. In this example I just put it hard coded. But you could make a call to the graph API from here.
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static IActionResult Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string[] roles = {"Admin", "Employee"};
var adminrole = new {
role = roles
};
return new OkObjectResult(adminrole);
}
// string email = req.Query["email"];
// string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
// dynamic data = JsonConvert.DeserializeObject(requestBody);
// email = email ?? data?.email;
Your token should now contain the roles.
{
"typ": "JWT",
"alg": "RS256",
"kid": "H-0"
}.{
"iss": "https://demo.b2clogin.com/9729/v2.0/",
"exp": 164,
"nbf": 1634,
"aud": "4a12ea396",
"given_name": "Tim C",
"family_name": "C",
"name": "Tim",
"idp": "google.com",
"sub": "adc1",
"role": [
"Admin",
"Employee"
],
"scp": "demo.write demo.read",
"ver": "1.0",
}.[Signature]
Upvotes: 3