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.

Dependencies

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:

<strong><em>You have JavaScript disabled, so we can’t embed the code example here. See the <a href=”https://gist.github.com/4182440″>example</a> at GitHub. </em></strong>

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.

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 New-MsolServicePrincipalCredential:

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.

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:

Now you should be able to display your user’s group memberships in the view:

Wrapping up

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.

Actually, there is a somewhat valid reason for that. AAL also contains the things you need to enable federated authentication for your GUI application — a chromeless, embedded IE window. That’d be the reason. But it still kinda feels wrong to reference S.W.F from a web app… 🙂

The error is:AAL 0x80100018: Token request from Access Control service failed. Check InnerException for more details

ACS50000: There was an error issuing a token. ACS50001: Relying party with name ‘00000002-0000-0000-c000-000000000000/graph.windows.net@XXmydomainhereXX.onmicrosoft.com’ was not found. Trace ID: a3fc144b-53a3-4573-b3fd-a78bae0da20dTimestamp: 2012-12-19 08:22:41Z

So, the code is failing to get the token that it needs to call the Graph stuff. What I can’t work out is why the token request is failing. I’m probably doing something stupid, or perhaps the Graph interface has changed subtly since the blog was written.

The code I wrote alongside with this blog post still seems to work with my setup, so it seems more likely to me that you’ve encountered yet another way this can go wrong.

From the error message, the problem appears to be the relying party name. Now, it looks correct to me, so just to be on the safe side, let’s see if I’ve made an incorrect assumption in my post.

Fire up the MSOL PowerShell, run Import-Module MSOnlineExtended -Force and then try:Get-MsolServicePrincipal | Select DisplayName,AppPrincipalIdOne of the returned entries should be named Microsoft.Azure.ActiveDirectory. Verify whether or not it has the same AppPrincipalId I’ve hard-coded in my example (00000002-0000-0000-c000-000000000000). If it doesn’t, try changing the constant to whatever the ID is in your case.

Lauri, Thanks for the prompt response. I have checked that the GUID is as expected, so it’s not that.

The four constructor parameters are:

Domain – as expected.
TenantId – checked that is the same as returned as TenantId within the list of claims returned by the SSO operation.
AppPrincipalId – checked that it is the Id of my application as returned by Get-MsolServicePrincipal.
Symmetric Key – I have one from when the Service Principal was created (which I am using successfully for SSO), and another from when I created the Credential. I have tried both here with the same result.

To try and nail it down, I have tried an incorrect domain – that results in a different error message: There was an error deserializing the object of type Microsoft.WindowsAzure.ActiveDirectory.Authentication.

ErrorResponse. Encountered unexpected character ‘T’.

I have also tried an incorrect Tenant Id – Interestingly, that gives the original “relying party not found error”.

Just for kicks, try to replace the AzureAppPrincipalId constant with the value "AzureActiveDirectory" instead of the GUID. It looks like the SPN for AD in O365 might be different from a pure WAAD tenant.

That updates the list of SPNs for Azure AD with values that are otherwise identical to the ones already there, but with the GUID AppPrincipalId instead of AzureActiveDirectory. That seemed to do the trick for me. 🙂

Of course, the constant was AzureAppPrincipalId, not AzureAdPrincipalId…Oh, and in case it wasn’t obvious before, I was able to reproduce your issue with our O365 subscription and make it work with the stuff I put in the gist. 🙂

To be more specific, the file version of C:WindowsSystem32WindowsPowerShellv1.0ModulesMSOnlineExtendedMicrosoft.Online.Administration.Automation.PSModule.dll should be 1.0.5288.0 (or newer, but that’s the version I use).

I get this error
AAL 0x80100018: Token request from Access Control service failed. Check InnerException for more details

{“ACS50027: JWT token is invalid. ACS50027: Invalid JWT token. The token is not yet valid.nValidFrom: ’02/07/2013 08:17:00’nCurrent time: ’02/07/2013 08:11:12′ rnTrace ID: a59f74b8-5e27-4253-aa39-d9f27bd96801rnTimestamp: 2013-02-07 08:11:12Z”}
but when I tried the same application in different windows8 laptop that works fine. but I get the same error in my other windows8 laptop.

please let me know if i need to install anything?
I just installed vs2012, AAL package . anything else do i need to install?

From the error message, it looks like you’re hitting some sort of time synchronization issue. Since it works on one computer and not the other, can you verify that the problem machine has its clock set to the correct time?

Hi, thanks for the set of articles. I am having an odd issue and not entirely sure why. Hopefully something simple. I have copied in the class you outline and updated the namespaces. All is building apart from it is stating that the ‘admin2.ActiveDirectoryGraph.Microsoft.WindowsAzure.ActiveDirectory.DirectoryDataService’ does not contain a definition for ‘Groups’ and the same for users, relating to the GetUserGroups method.

The Graph API has been updated, and since Visual Studio’s Service Reference tool doesn’t provide a way to set the API version header, you’re getting a newer contract. I haven’t familiarized myself with the API changes yet, so I’m not sure what to tell you. I’ll try to look into it Real Soon Now [tm].

Thanks Lauri, if you could work that into an updated post that would be fantastic. I have tried to update your code to make it work but I’m afraid I fall short of your skills. I can get it to complile but get runtime error after error.

Lauri, should have mentioned also. I did look at the updated sample they have done, it works well but I struggled when attempting to move the code to a helper class or action filter rather than hanging off the controller where my actions are. I am showing my inexperience again, but because it using httpcontext I couldn’t work out how to move the code away from the controller.

Sure, http://code.msdn.microsoft.com/Write-Sample-App-for-79e55502#content. Each controller has an entry at the top using HTTP context and then actions have the code to do the work. I couldn’t work out how to put the code into helpers or filters. I tried doing something with HTTPCONTEXT and also tried to pass the directoryservice into the helper but couldn’t get it to work.