Getting Azure Active Directory groups in asp.net core project
Asked Answered
P

2

34

I created a new project using Visual Studio 2015 and enabled authentication using work and school accounts against Azure Active Directory. Here is what the generated configure function looks like:

app.UseStaticFiles();
app.UseCookieAuthentication();
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
    ClientId = Configuration["Authentication:AzureAd:ClientId"],
    ClientSecret = Configuration["Authentication:AzureAd:ClientSecret"],
    Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
    CallbackPath = Configuration["Authentication:AzureAd:CallbackPath"],
    ResponseType = OpenIdConnectResponseType.CodeIdToken
});

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

Here is the rudimentary action code trying to get user groups:

public async Task<IActionResult> Index()
{
    var client = new HttpClient();
    var uri = "https://graph.windows.net/myorganization/users/{user_id}/$links/memberOf?api-version=1.6";

    var response = await client.GetAsync(uri);
    if (response.Content != null)
    {
        ViewData["response"] = await response.Content.ReadAsStringAsync();
    }

    return View();
}    

What do I need to use or change this code to make sure I can get user groups? Currently, the response is:

{  
   "odata.error":{  
      "code":"Authentication_MissingOrMalformed",
      "message":{  
         "lang":"en",
         "value":"Access Token missing or malformed."
      },
      "values":null
   }
}
Payoff answered 11/8, 2016 at 5:10 Comment(4)
Hi Kiran, have you figured out anything in regards to this question. I'm having the exact same problem. Thank you!Vertievertiginous
Kiran, if you like my answer, please select it. Thank you.Vertievertiginous
Check your index method, you are creating an instance of HttpClient() and setting URL. But, you never set a Authorization header before calling GetAsync(). Try reading about Events and OnTokenValidated method of UseOpenIdConnectAuthentication that should help you obtain the access token and could lead you to solution.Bret
Not sure if this is what you're looking for but way easier than using Graph IMO for obtaining roles and groups. I created a .Net Core app that uses Azure AD which gets fed from the on site company AD. Roles/Users can be managed on AD which gets pushed up to Azure AD and the app roles defined are what the app will use. learn.microsoft.com/en-us/azure/architecture/…Karlotte
V
2

I spent the last 2 days trying to figure this out and finally got it. Azure AD is a moving target and with ASPNETCORE still maturing most documentation on how to access the Azure AD Graph is outdated. So as of right now this is how you would go about access the Azure AD Graph.

  1. Take note of your app's clientid
  2. Register your app with Azure Active Directory
  3. Generate a Key in that registration and take note of it (you can only view it right after it's created)
  4. Take note of your 'Tenant Name' (you can also use the Tenant ID)

Then you will use the above info to generate a Access Token, then use that token to make calls to the Graph.

public async void GetUsers()
    {
        // Get OAuth token using client credentials 
        string tenantName = "your-tenant-name.onmicrosoft.com";
        string authString = "https://login.microsoftonline.com/" + tenantName;
        AuthenticationContext authenticationContext = new AuthenticationContext(authString, false);
        // Config for OAuth client credentials  
        string clientId = "your-client-id";
        string key = "your-AzureAD-App-Key";
        ClientCredential clientCred = new ClientCredential(clientId, key);
        string resource = "https://graph.windows.net";
        AuthenticationResult authenticationResult;
        try
        {
            authenticationResult = await authenticationContext.AcquireTokenAsync(resource, clientCred);
        }
        catch(Exception ex)
        {
            throw new Exception(ex.Message, ex.InnerException);
        }

        var client = new HttpClient();
        var request = new HttpRequestMessage(System.Net.Http.HttpMethod.Get, "https://graph.windows.net/your-tenant-name.onmicrosoft.com/users?api-version=1.6");
        request.Headers.Authorization =
          new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
        var response = await client.SendAsync(request);
        var content = await response.Content.ReadAsStringAsync();
    }

One other huge gotcha that you may find that I ran into and several forums are discussing is if you get a Authorization_Request_Denied error or Insufficient_Permissions error. This is resolved by running a PowerShell command to give the application you registered with Azure AD "Administrator" permissions. Requests to MS Graph API gives me "Authorization Request Denied - Insufficient privileges to complete the operation"

The powershell command you want to run is

Connect-MsolService
$ClientIdWebApp = '{your_AD_application_client_id}'
$webApp = Get-MsolServicePrincipal –AppPrincipalId $ClientIdWebApp
#use Add-MsolRoleMember to add it to "Company Administrator" role).
Add-MsolRoleMember -RoleName "Company Administrator" -RoleMemberType ServicePrincipal -RoleMemberObjectId $webApp.ObjectId

Hopefully this helps. Let me know if you think any refining needs to be made.

Vertievertiginous answered 17/2, 2017 at 18:53 Comment(3)
You do not need to add the service principal to the Company Admin role.. It only requires the Read All Groups delegated permission/Read directory data app permission. If you get that error then it means admin consent has not been given or the permission was not requested.Reinareinald
Ummm.. thanks for the -1 @juunas. The answer was more about everything above that extra tidbit. And contrary to your wisdom above I had given the app "Read All Groups delegated permission/Read directory data app permission" and it still had insufficient permissions. Only after I applied the recommended bonus solution above did it finally serve back my request. I hope my answer assists someone who has encountered this same problem.Vertievertiginous
Well, I have implemented such an app with those permissions. Making a principal the highest admin role available is usually just not a good idea. Since the principal can in effect reset any user's password at that point.Reinareinald
B
1

Code is much simpler with Graph client

var serviceRoot = new Uri(@"https://graph.windows.net/"+ tenantID);
var activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
    () => Task.FromResult(authenticationResult.AccessToken));

// Fetch more user details from the Graph
var user = await activeDirectoryClient.Users.GetByObjectId(userObjectID).ExecuteAsync();
// fetch all groups (DG + SG) and roles transitively for the user
var userGroups = await user.GetMemberObjectsAsync(securityEnabledOnly: false);
Barracuda answered 7/3, 2019 at 3:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.