Azure AD B2C - Role management [duplicate]
Asked Answered
L

1

27

I have an Asp.NET MVC Application connected with Azure AD B2C.

In the Administrator settings I've created an Administrators Group:

enter image description here

In my code I would like to use [Authorize(Roles = "Administrator")]

With regular Azure Active Directory it was easy to add (just 3 lines of code). But for the Azure AD B2C I cannot find any tutorial or example in the web which is working. Maybe you can tell me what i need to modify.

Here is the ConfigureAuth method of my Startup.Auth.cs

public void ConfigureAuth(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            // Generate the metadata address using the tenant and policy information
            MetadataAddress = String.Format(AadInstance, Tenant, DefaultPolicy),

            // These are standard OpenID Connect parameters, with values pulled from web.config
            ClientId = ClientId,
            RedirectUri = RedirectUri,
            PostLogoutRedirectUri = RedirectUri,

            // Specify the callbacks for each type of notifications
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                RedirectToIdentityProvider = OnRedirectToIdentityProvider,
                AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                AuthenticationFailed = OnAuthenticationFailed,
            },

            // Specify the claims to validate
            TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name"
            },

            // Specify the scope by appending all of the scopes requested into one string (separated by a blank space)
            Scope = $"openid profile offline_access {ReadTasksScope} {WriteTasksScope}"
        }
    );
}
Linder answered 25/8, 2017 at 16:29 Comment(0)
E
28

Azure AD B2C does not yet include Group claims in the token it sends to the application thus you can't follow the same approach as you outlined with Azure AD (which does include group claims in the token).

You can support this feature ask by voting for it in the Azure AD B2C feedback forum: Get user membership groups in the claims with Azure AD B2C

That being said, you can do some extra work in this application to have it manually retrieve these claims the group claims and inject them into the token.

First, register a separate application that'll call the Microsoft Graph to retrieve the group claims.

  1. Go to https://apps.dev.microsoft.com
  2. Create an app with Application Permissions : Directory.Read.All.
  3. Add an application secret by clicking on Generate new password
  4. Add a Platform and select Web and give it any redirect URI, (e.g. https://yourtenant.onmicrosoft.com/groups)
  5. Consent to this application by navigating to: https://login.microsoftonline.com/YOUR_TENANT.onmicrosoft.com/adminconsent?client_id=YOUR_CLIENT_ID&state=12345&redirect_uri=YOUR_REDIRECT_URI

Then, you'll need to add code the following code inside of the OnAuthorizationCodeReceived handler, right after redeeming the code:

var authority = $"https://login.microsoftonline.com/{Tenant}";
var graphCca = new ConfidentialClientApplication(GraphClientId, authority, GraphRedirectUri, new ClientCredential(GraphClientSecret), userTokenCache, null);
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };

try
{
    AuthenticationResult authenticationResult = await graphCca.AcquireTokenForClientAsync(scopes);
    string token = authenticationResult.AccessToken;

    using (var client = new HttpClient())
    {
        string requestUrl = $"https://graph.microsoft.com/v1.0/users/{signedInUserID}/memberOf?$select=displayName";

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);

        HttpResponseMessage response = await client.SendAsync(request);
        var responseString = await response.Content.ReadAsStringAsync();

        var json = JObject.Parse(responseString);

        foreach (var group in json["value"])
            notification.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, group["displayName"].ToString(), System.Security.Claims.ClaimValueTypes.String, "Graph"));

        //TODO: Handle paging. 
        // https://developer.microsoft.com/en-us/graph/docs/concepts/paging
        // If the user is a member of more than 100 groups, 
        // you'll need to retrieve the next page of results.
    }
} catch (Exception ex)
{
    //TODO: Handle
    throw;
}
Exospore answered 27/8, 2017 at 8:38 Comment(12)
First big thanks for your answer! I have just 2 questions left about it. Where should i add that URL (Step 4) and what is the Redirect uri (is this the reply uri of the b2c?) ? Another question to the Code: What sould i fill in the variables: - GraphClientId - GraphRedirectUri - GraphClientSecret - userTokenCache And VisualStudio is calling an error message at: new c.Claim Big thanks for your help :-)Linder
Made updates to further clarify app registration instructions and address the c.Claim issues.Exospore
GraphClientID = the Application ID of the app you registered, GraphSecret = the Application Secret, GraphRedirectUri = the Redirect URI you specified, userTokenCache should already be defined from the code that's already in that OnAuthorizationCodeReceived from the sample.Exospore
Step 5 returns me a URL including this error message: error=access_denied&error_description=AADSTS50020%3a+We+are+unable+to+issue+tokens+from+this+api+version+for+a+Microsoft+account.+Please+contact+the+application+vendor+as+they+need+to+use+version+2.0+of+the+protocol+to+support+this.%0D%0ATrace+IDLinder
The 2 things im not sure about: The Plattform Redirect Uri: Should this be the Website URL where the MVC Application is hosted or the AzureB2C Domain? The Application Permissions show: Directory.Read.All (Only Administrators) I cannot delete the "Only Administrators"Linder
Finally get it working - If anybody else need the answers: Redirect URI is the same as in the azure portal. In the link you need to change "common" to your b2c tenant ID. Thanks again for your help SacaLinder
seems like the same question/issue hereNuke
Thank you so much for this post. I googled the heck out of this problem and tried several other solutions, but none worked. This one does. One issue I have is with the Graph Client app. I need my Web API to also get group membership, so I tried to register another app as a Web API. I couldn't get the consent step to work. I used that app's client ID etc, but the consent page shows an error that the reply URL is wrong. If you have any ideas, I'd appreciate them. E.g., do I even need another app, or can my API just use this one somehow? Regardless, thank you very much for the helpful info.Coquito
Wouldn't modifying the token break the signature of the JWT? These groups are being added to the token, right?Nuke
You are not modifying the actual token. You are adding claims to the .Net abstraction of the token that gets generated in memory after the token is validated.Exospore
How do you add these claims if you are retrieving the access token with msal.js in an Angular frontend and sending it to a .net core backend?Dirham
At the current time, I believe the link "apps.dev.microsoft.com" is no longer valid. I believe the new system is portal.azure.com. However, I am not sure how to do step 2 at that location: "Create an app with Application Permissions : Directory.Read.All." Can any one give guidance on this?Christianchristiana

© 2022 - 2024 — McMap. All rights reserved.