This is the third part in my series of posts on Windows Azure AD. In this post I go through the steps required to get your application talking to the AD Graph API, and the things that stumped me along the way. The reason we’re interested in the Graph API to begin with is that WAAD Authentication provides us with the user’s identity, but doesn’t tell us anything else about them. If we want more details, such as group memberships, we need to do some extra work.
We begin this part by adding a new Service Reference to the project. For the address of the service, type http://graph.windows.net/offbeatdemo.onmicrosoft.com (replacing offbeatdemo.onmicrosoft.com with your own tenant domain name) and click “Go”. After a moment of waiting, Visual Studio should generate the necessary metadata files. Here you can give your service a namespace – remember, it’s relative to your project’s default namespace, so let’s call it “ActiveDirectoryGraph”.
Once you hit OK, the service reference is generated as per usual. This is where the fun begins. Go to the References node in your project, right-click and select “Manage NuGet Packages…”. Select “Online” from the left, click on the search box and type in “Microsoft.WindowsAzure.ActiveDirectory.Authentication” and you should see a single matching package.
Click on “Install” to have NuGet fetch the library for you. The library in question is the Windows Azure Authentication Library, or AAL for short. It has all kinds of features, but the reason we need it is to authenticate our application so it can make Graph API requests. Somewhat counterintuitively, AAL depends on System.Windows.Forms of all things, so before your code will compile, you will need to add that as a reference to your project.
Using the API
Create a new class in your project – you can call it what you like, but I’m calling mine “GraphClient”. Paste in the following code – you may have to change some namespaces, but if you’ve added the service reference and the AAL package correctly, it should compile as is:
I’m not going to go through the implementation details of the class now – if you’ve got questions or feedback, leave a comment here or in the gist at GitHub. In order to use this class, what you need to do is find out some details about your tenant domain and Service Principal. It’s not entirely obvious why, but the only place where I’ve found the tenant id so far is the FederationMetadata.xml file (as documented in the article Integrating Multi-Tenant Cloud Applications with Windows Azure Active Directory) – note that the file I linked to is the federation metadata for my demo tenant domain, so you need to change the URL to get your own metadata. Locate the entityId attribute on the EntityDescriptor tag.
The entityId attribute looks like this:
spn:00000001-0000-0000-c000-000000000000@a071bf68-ee1d-46aa-ac6d-cfddf3826050 – the emphasized part after the @ sign is the tenant id. Yours will be different from mine of course – copy the id somewhere handy, because you will need it soon. You’re also going to need the app principal id of the service principal you created in the previous installment. Finally, you’ll need to grant your application the right to read the directory, and create a symmetric key known to both WAAD and your application – it’s a key you will use to sign your requests, so WAAD will know it’s you making them. Here’s how you do all that: open the MSOL module for PowerShell and use
Connect-MsolService to connect to your WAAD tenant. Run
Import-Module MSOnlineExtended –Force to make all the commandlets available, and then run
Get-MsolServicePrincipal | select DisplayName,AppPrincipalId to list your service principals.
PS C:\Windows\system32> Get-MsolServicePrincipal | select DisplayName,AppPrincipalId DisplayName AppPrincipalId ----------- -------------- Microsoft.Azure.ActiveDirectory 00000002-0000-0000-c000-000000000000 Microsoft.Azure.ActiveDirectoryUX 0000000c-0000-0000-c000-000000000000 WAADDemo App e8a3050f-0c61-46bd-9808-ff7dd5dcdb4b
The resulting list will show you the app principal id (in this case,
e8a3050f-0c61-46bd-9808-ff7dd5dcdb4b) – copy it somewhere handy. Next, we use that to create a new symmetric key with
PS C:\Windows\system32> New-MsolServicePrincipalCredential -AppPrincipalId e8a3050f-0c61-46bd-9808-ff7dd5dcdb4b The following symmetric key was created as one was not supplied JH0QbohY5/+IW25zzukjuwPjr6mpnMhgicgVA4SfF9A=
Save the symmetric key somewhere too. As far as I know, there is no way to restore the value if you lose it – you’ll have to create a new key instead. You’ve got everything your application needs, but there’s still one more thing left to do: granting privileges.
PS C:\Windows\system32> Add-MsolRoleMember -RoleName "Service Support Administrator" ` -RoleMemberType ServicePrincipal -RoleMemberObjectId 3dc125e6-d518-40d2-9392-87a03dac8f68
The “Service Support Administrator” role grants read-only access to the directory. The
RoleMemberType switch is needed to inform WAAD that we’re granting the privilege to an application instead of a user or a group, and the
RoleMemberObjectId switch identifies the Service Principal. Note that the Object Id is different from the
AppPrincipalId we used earlier – if you don’t have the Object Id written down anywhere, you can use
Get-MsolServicePrincipal | select DisplayName,ObjectId to get it. Now, you can use the collected values to create an instance of GraphClient and use it. Add this to a controller action:
var client = new GraphClient("offbeatdemo.onmicrosoft.com", "a071bf68-ee1d-46aa-ac6d-cfddf3826050", "e8a3050f-0c61-46bd-9808-ff7dd5dcdb4b", "JH0QbohY5/+IW25zzukjuwPjr6mpnMhgicgVA4SfF9A="); var groups = client.GetUserGroups(User.Identity.Name); return View(groups);
Now you should be able to display your user’s group memberships in the view:
None of this was particularly difficult to do from a programming perspective – the trick is finding all the information you need! It doesn’t much help that most of the examples out there deal with either SaaS applications that are registered in the Seller Dashboard or applications that use ACS instead of WAAD. The steps are largely the same, but the places where you look for IDs and keys are wildly different. Merely listing the user’s group memberships isn’t very interesting. Now that we’ve got them, we could use them for authorization within the application – which is what we’re doing in the next part of this series.