I don’t know about you guys, but I use Microsoft Azure all the time (it’s not Windows Azure any longer). Not for everything I do, I still have servers at home and at work, but if I need to deploy something to "the cloud" that cloud is often Azure. One of the features in Azure I’ve taken a liking to recently is Azure Active Directory, which lets you either extend your current on-premise AD or setup a cloud-only AD. Since this AD provides APIs as well as the UI management tools you would expect by default this gives you the benefit of not having to implement a separate identity system for stuff that you create, and users can reuse the credentials they already have instead of having to remember multiple logins.
The general workings of Azure AD works may be familiar to you already, so I’m not going to do an introduction on how to get started with Azure AD. If however it doesn’t ring a bell you may check out MSFT’s site:
To follow along with this article you will need access to an Azure AD tenant. It doesn’t matter if it’s cloud only or the full DirSync experience. The code stays the same.
When you break it down to the basics you could say that Active Directory is just a database. For a long time it’s been possible to use AD as a database by "extending the schema", but if you’ve ever tried to convince a sysadmin that "hey, my app wants to put extra stuff into your directory" you will know that’s a pretty tough sell. (I am equally hard to convince if an app I didn’t create wants to insert config data into my AD, so I don’t blame the admins.)
Microsoft recently introduced a new feature called "Directory Extensions" to Azure Active Directory. Still only in preview, but that’s not a problem as far as introducing it to the lab 🙂 These extensions live exclusively in the cloud, (if this will change later on I do not know), so they do not get synced back to your on-prem AD.
A blog post from the AAD Graph Team should give you an idea:
Graph API is the term for the RESTful interface that developers use to access the Azure Active Directory tenants; you don’t get to talk directly to the underlying files that make up the directory 🙂
The idea is that your app might be in the possession of data that it would make sense to attach directly to the user object in the identity directory, and/or data that might be of interest to other apps. This data should be inserted in, and extracted from, Active Directory in a manner that doesn’t interfere with the internals or break something.
It’s not necessarily easy at first glance to understand what this feature could be used for, or how it works, so I thought I’d try to create a walkthrough where I implement a simple scenario to illustrate what you can leverage these extensions for.
I’ve previously covered the YubiKey products, and how these can be used for multi-factor authentication:
One “drawback” that I mentioned is that these keys would have to be registered by the user, and how you need to do this in an elegant manner. Yes, you could use the built-in identity system in .Net. Yes, you could put that information into a SQL database. But what if I want to use this for logging in to more than one web app? The “Simple identity” subsystem is not designed to be a single sign on system. A SQL database requires careful design and management of logins if it is to be used by more than one app.
Using Active Directory seems to be more flexible as the identity store. And the id of the YubiKey could very well be linked directly to the user object in AD. Let’s see if we can cook up something based on Directory Extensions.
As this example focuses on the use of AAD, and not the use of YubiKeys, I have left out some of the necessary code to properly handle actual YubiKeys. (Making sure the One Time Password provided by the key is valid so you can’t just fake it by typing in random characters as the id.) This means you can also follow along even if you don’t have a YubiKey. If you want to use real keys code snippets provided in my previous articles should be possible to adapt and integrate into this code.
I chose ASP.NET Web Application as I often do.
Change authentication to Organization Accounts and Multiple Organizations. Make sure you select an Access Level of "Single Sign On, Read and write directory data".
I chose the multi-tenant app both to be able to access this from multiple tenants, and due to the way authenticating against the Graph API is handled when using this template. With this template I can acquire a token using client id & secret (client in this case being my web app). If you choose single tenant or any of the other templates the code in this article will not work without an amount of tweaking.
Let the wizard build out your web app, and load up the solution explorer.
I’m just building basic models that reflect the JSON data the Graph API returns to me. If you want to see what this looks like in it’s raw form the easiest thing to do is to go to http://graphexplorer.cloudapp.net and use the demo tenant.
The model definitions look like this:
You’ll notice there are a couple of different classes here to support other operations, but the important details are in the UserDetails class.
Let’s start by copy-pasting the code, and I’ll provide some highlights below:
Public async Task<ActionResult> Index()
The Index method gets the user object for the currently logged in user. It sets up the authentication parts to build the header needed to access the Graph API, and executes an HTTP GET to get a JSON object returned. I had to pull off a slight hack to be able to read the extension I’m looking for. This is because the Extension Property will have a guid in it’s name, so I’m not able to decorate this properly in my model in advance. Unknown properties cannot be serialized by default, so after populating the user object I manually extract the extension value I’m interested in by acquiring the actual name of the extension.
There’s also an HTTP POST version of the method to, well handle the POST/form submit 🙂 This calls into helper methods for checking if the extension property is registered, and register it if it isn’t there. There’s also hooks into registering a key and unregistering it afterwards. This means you can only have one key assigned per user, but at the moment the API doesn’t accept arrays either, so this is by design.
I’m not going to cover the helper methods in detail, but if you’re not familiar with the Graph API you’ll notice that it’s all about building urls and apply the correct verbs depending on whether you’re reading or writing data. (Much like you would expect from a RESTful API.)
Note that I’m using an api-version parameter equal to "1.21-preview". This will likely change in the future, but currently the directory extensions feature is not working in the released versions of the Graph API.
It’s not exacty a very jazzy layout, but you are of course free to create your own css stylings:
You should now be able to build and run the app. You’ll be greeted by the default index page provided in the template. You’re probably tempted to hit the Sign In link, but if you do so you will get a yellow screen of death like this:
This is because you have to sign up for your application first. This action has to be performed even for the tenant you are using to develop this web app. The sign up process will have you accepting the risk there is to letting a "third-party" access your Azure Active Directory tenant. This is the same process as other tenants will need to go through as well.
After signing up, and signing in, go to https://localhost:x/AzureAD (just tag on AzureAD to whatever url your site runs on by default):
This is the fake YubiKey part. Normally you would insert your key and tap it so it filled in the value for you, but I just entered "1234" as the id.
When you click the Register YubiKey button "magic" will be performed in the background, and the text value will change to “Unregister YubiKey” to indicate the id has been saved into Azure AD and the user object. And unsurprisingly it will be removed from Azure AD when you click the button again. At least I hope it works like this for you as well, and don’t fail with some cryptic error message.
You cannot test this with Graph Explorer at the moment, so if you want to verify that things are working correctly behind the scenes I recommend you have Fiddler running in the background to capture the traffic. You should be able to understand most of it by looking at the requests and responses.
Since there’s a certain amount of code copy/pasted here it’s starting to look slightly lengthy at this point. By now we have a working web app for registering our keys, and you can play around in debug mode to figure out what we’re doing to make it work. In the next part I’ll show how to cook up something that will let us use these keys in a different app.