READ THIS FIRST

Update: 3-4-2016: If you're finding this blog and looking for information related to Azure Mobile Services, I'd strongly recommend checking out Azure Mobile Apps. Azure Mobile Apps is a new version (consider it a v2) of Azure's mobile backend support. All of the same features of Azure Mobile Services are there, with a lot of other very cool features to go along. You can read more about Azure Mobile Apps, and how to transition from Azure Mobile Services, here.

Identity is always a very important topic when it comes to securing resources online and accessing them from different sources.  One of the very popular ways of doing this in the enterprise is with something called Active Directory (AD).  To vastly generalize things, Active Directory is a system that keeps track of users and groups (that users can be in) and acts as an authentication and authorization service.  Programs can also use these groups and users to decide what users have access to what.  I know of at least a few people that would probably flay me for such a simplification of a pretty complex technology, but for today, this will do.  I’m sure somewhere there are stats on how many companies are using AD to manage their user infrastructure but I would easily guess it’s “a lot” (my unofficial rumor says it’s something like 90+% of top US companies).  The company I last worked for used AD quite heavily and all of the .NET applications I worked on or deployed were using AD to control permissions within the apps.  One challenge that people have had though is exposing these same resources externally.  Until recently, it wasn’t very easy to expose your AD structure outside your company’s datacenter.  Today we’ll talk about how you can do that. 

If you’d like to skip to the code, you can use the following links:

 

Taking AD to the Cloud

In the recent past, we launched something called Windows Azure Active Directory (WAAD).  This allows you to put your AD structure in the cloud.  What’s even more powerful to current users of AD is that you can integrate your on-premises AD with Azure AD.  Now you can have users authenticate internally (i.e. when they are sitting at their desk) as well as give them the ability to authenticate to your AD for any resources you’re hosting in Windows Azure.    Just this week, the Active Directory Authentication Library for .NET went into General Availability (GA) (ADAL) which makes it really simple to authenticate and access these locked down resources from .NET clients.  This is great news for anyone building .NET client apps (whether they are Windows Store, desktop, Windows Phone, or console apps) but it does leave those of us using iOS or Android devices out in the cold.  Thankfully I’ve worked out a solution to easily enable you to build apps that will authenticate against Windows Azure Active Directory so you can expose secured functionality and data to these common platforms.

The Authentication Flow

Regardless of if we’re building an app for iOS or Android, the flow of getting access to a resource using WAAD is going to be the same:

  • Client shows a webview displaying the Azure Active Directory login screen.
  • User authenticates using their WAAD credentials.
  • WAAD redirects to a URL originally specified as a parameter to the webview load.  This redirect includes a code.
  • Client then uses that code to request an access token (this can happen behind the scenes and does not require user action).
  • WAAD returns an Access Token to the client (amongst other information explained below).
  • Client can make requests to the secure resource (web service in this case) using that token as part of an Authorization header.

If you dug into the ADAL mentioned earlier, you’d see that it’s really facilitating the same flow.  It transparently handles a few things we’re not going to cover today but most of those things (like caching the access token and asking for a new one when it expires) should be relatively easy for you to implement (and maybe I’ll add additional articles about how to handle them).  Below, after we talk about setting up the server, we’ll look at the specific locations and URLs we need to deal with for the above flow. 

Setting up Azure

First and foremost, if you don’t already have a Windows Azure subscription, you can sign up for an absolutely free trial here.  For the bulk of the work in setting up your WAAD instance and our web service, I’m going to point you to different article on Securing a Windows Store Application and REST Web Service using Windows Azure AD.  You’ll want to follow the flow of this tutorial until you get to the section on Creating the Windows Store Application Project.  Since we’re not concerned with Windows Store here, we can skip this. 

Handling a different Redirect URI

There is one other section we need to perform for our clients to work though and that is under Registering the Todo Client and Service with Windows Azure AD.  Follow along with that and go to https://graphexplorer.cloudapp.net.  There you’ll need to sign in with the admin credentials you created for your WAAD account.  Lastly, when you are at the Create Application Permission screen, for the Client App URL you’ll want to enter the redirect URL that your client apps will catch.  If you want to go along with how I have things set up in the source code already, just enter com.cmr.waadtest://authorize in that value. 

What to do if you’re having issues so far

Note that if you’re not keen on doing .NET development or think something may not be working correctly on your service side, you can download the completed source code for the web service (and the Windows 8 client) here.  You’ll just need to put in the appropriate settings in the global.asax (i.e. the domainName and audience). 

Getting away from localhost

If you’re going to be testing the clients using the simulator / emulator, then the steps described in the set up above, where you’re using localhost and running the service locally would be fine.  Of course you’ll need to figure out how to expose that localhost site to your iOS simulator running on a different computer which can all be a little confusing.  The most straightforward way to handle things is to deploy the website code to Windows Azure Websites.  All you have to do for this to work is change any of the URLs that are using localhost to the URL of your Windows Azure Website.  This includes where you have things set up in your AD account as well as redoing the graph explorer for the correct URL and changing the URL in the web service source code in the global.asax.  This can be a little confusing and may not be for the faint of heart so ask questions in the comments if you need clarification.

Running the Clients as is

At the time of posting, I’m leaving up the AD account and Website that would allow users to authenticate inside the apps without any changes.  Provided things are still up and running (I haven’t had to take down the service / AD account) you should be able to authenticate to the apps right away using the following credentials:

If those credentials aren’t working for you, assume the services aren’t up and proceed with setting up everything on the server side and then configuring your client.

Configuring the Clients

Rather than walk you through every line of the code for both clients, I’m going to describe the specifics of each of the authentication flow steps above.  You can download the client source code from GitHub at the links below:

Regardless of which client you are going to work with, before you can run you need to change some values located in either Constants.h or Constants.java.  These values point to specific things we have set up in Azure or Graph Explorer.  I’ll try to explain where you should get each of these values from:

  • LOGIN_URL - this can stay as https://login.windows.net/ as that is the URL we’ll send users to login to.
  • DOMAIN - this is the domain you set up in the Azure portal and should resemble something.onmicrosoft.com
  • CLIENT_ID - this is the value you got out of the graph explorer when you created the permission.  It should be the Client ID for the Client Application and will look like this fa94de18-3636-447e-8986-99db18aeac85.
  • REDIRECT_URI - this is the URI you put into the graph explorer when you created the permission and was the Client App URL.  If you used the value suggested above, you can leave this as is: com.cmr.waadtest://authorize.
  • RESOURCE - this is the URL of your website and needs to match up what you entered when you created the app permission in the graph explorer.  Since I pushed my site to Windows Azure websites, my URL was http://win8webapp.azurewebsites.net/.  Make sure you include the trailing slash as entered in for the Service App ID URI.
  • SERVICE_ENDPOINT - this is the rest of the URL for your website that would be used to access your web service.  If you have used the sample site, you can leave it as api/todolist.

That should be it for client configuration.  There are a couple source code files you’ll need to download and add to the iOS app.  You can read more about these files in the GitHub Readme or open the ThirdParty/thirdparty.txt file and follow the instructions there. 

Walking through the Clients

If you’ve implemented an OAuth authentication flow, what we’re about to walk through shouldn’t be too weird.  Even if you haven’t, once you see the different steps, it should make a good deal of sense to you.  With both clients, after launching the first thing we do, is wait for the user to tap the Authenticate button.  Once they do, we pop open a web view which will load this URL:

https://login.windows.net/<strong>christesttwo.onmicrosoft.com</strong>/oauth2/authorize?<strong>response_type</strong>=code&amp;<strong>resource</strong>=http://win8webapp.azurewebsites.net/&amp;<strong>client_id</strong>=fa94de18-3636-447e-8986-99db18aeac85&amp;<strong>redirect_uri</strong>=com.cmr.waadtest://authorize
This URL comprises the windows.net login URL, our domain (christesttwo.onmicrosoft.com), the response type we’re looking for (code), the resource we want to access (http://win8webapp.azurewebsites.net/), our client ID (the alphanumeric string), and our redirect URI (com.cmr.waadtest://authorize).  In both iOS and Android we have the capability to intercept different URLs loading in our webview.  We use this capability to catch the redirect after the user logs in (login.windows.net will redirect back to the URL we passed in as a parameter).  When the user does login, the redirect will be to a URL that looks like this:
com.cmr.waadtest://authorize/?<strong>       
code</strong>=AwABAAAAvPM1KaPlrEqdFSBzjqfTGE2vpMXa2tSeyt5abHfypa7ylOkmSMtkxWQWEDOkOSd5nXUCz1_GAzYPT4n5YOIlhKxyaBEprf-UxKz0SHK3E0ZRi8FtZzKuAgl6TvKCapcnlf4K0aeNlSJcgaysEMTFVbFcJ8oTBqIMjtKbPB_JhbfSMTHbSvYbxxdPK5FNOO3FmsTw-BrDz3BHrLxJioSSRlmOZ9LqxHFUh4twTMd2hhaxT69m7BozUsVYa0iGRJqVi4PeK89G17eET03tIDCGxL8BL0oMj63YskwTEgAGq-RRDHUTY_6_Pn63rn6G9DlRNd3199LnuFBXgcU2K338TMFdNjI1qVaD8gfKfKRSiF53ZWfi8DFtanSFgQvlXkbIhNhYELojnK7BwWooQaXzoCAA&amp;<strong>session_state</strong>=00a1cb02-67d2-42d5-bf03-18182d81d521
The important part here is the code that comes back.  We need to pull this out.  The second step in the client applications is for the user to tap the Get Token button.  This step is drawn out for your benefit in understanding the different steps.  In reality, you could just go straight from getting the code to getting a token (and I wouldn’t advise requiring user action to fetch that token).

Getting a Token

Once the user taps the Get Token button, we then do a post to this URL:

https://login.windows.net/christesttwo.onmicrosoft.com/oauth2/token

This URL is very similar to the first one except we’re not passing any query string parameters and instead of the endpoint being authorize we’re going to token.  This is the endpoint in the AD login service that will return a token to us (provided we pass the right data into the body) as opposed to asking a user to authenticate.  To this URL, we need to pass the following data in URL Form-Encoded format:

  • our Client ID
  • the code we received previously
  • the grant type (authorization code)
  • the redirect URI (this just has to match up with what we sent previously and isn’t used as a redirect)

We also need to specify that we expect application/json as the response type and that we’re sending over application/x-www-form-urlencoded data as the Content-Type.  We post that data to the above URL and provided it’s all valid, we’ll get the following data back (in JSON format):

  • Access Token - this is the magic key we need to get into our web service
  • Expires In - how long until the token expires
  • Expires On - when does the token expire
  • ID Token - a unique ID for the user
  • Refresh Token - this token can be used to request (behind the scenes w/o user interaction) a new Access Token when that expires
  • Resource - this should match the resource we're using in our client app
  • Scope - what is the scope of the user permission
  • Token Type - what type of token have we received (in this case Bearer)

At this point, we have everything we need to make requests against our secured web service.

Making Calls

The client application / service functions as a very simple todo list.  We’re able to add items (which are stored temporarily in non-persistent storage) and can be received.  So we have two different methods:  get todo items and add a todo item.  I won’t go into what’s going on with talking to these methods in depth because they are very simple rest calls to our resource URL plus /api/todolist.  If we are fetching items, we do a GET request.  If we are adding an item, we perform a POST request.  When we post an item, we use JSON.  When we receive the todos, they are in JSON.  The only thing you need to make sure you do is set a HEADER on the request before it’s made with the name Authorization and the value:  Bearer <Access Token> where you put your access token in (and don’t use the carrots). 

Decoding Claims

There is one additional capability of each of the client apps and that is to decode the claims we receive as part of the Access Token.  The Access Token comes over in the following format:

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1THdqcHdBSk9NOW4tQSJ9.eyJhdWQiOiJodHRwOi8vd2luOHdlYmFwcC5henVyZXdlYnNpdGVzLm5ldC8iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9lZjg2YjIwYy03NzgyLTQ3M2UtOTQ1Zi01ODNiODhlYjczNWIvIiwiaWF0IjoxMzc5NjA3MjU3LCJuYmYiOjEzNzk2MDcyNTcsImV4cCI6MTM3OTYzNjA1NywidmVyIjoiMS4wIiwidGlkIjoiZWY4NmIyMGMtNzc4Mi00NzNlLTk0NWYtNTgzYjg4ZWI3MzViIiwib2lkIjoiMzllNmZiNGMtMzZmNS00ZDY3LWJmNGYtMTk4MTZiMTlmOTljIiwidXBuIjoidXNlckBjaHJpc3Rlc3R0d28ub25taWNyb3NvZnQuY29tIiwidW5pcXVlX25hbWUiOiJ1c2VyQGNocmlzdGVzdHR3by5vbm1pY3Jvc29mdC5jb20iLCJzdWIiOiI3MnpUa09vZ0NUQnh3ZmZIQ200b005ZFFOV3E0ZWNTbzc1SlA5N3dpVmxBIiwiZmFtaWx5X25hbWUiOiJ1c2VyIiwiZ2l2ZW5fbmFtZSI6InVzZXIiLCJhcHBpZCI6ImZhOTRkZTE4LTM2MzYtNDQ3ZS04OTg2LTk5ZGIxOGFlYWM4NSIsImFwcGlkYWNyIjoiMCIsInNjcCI6InVzZXJfaW1wZXJzb25hdGlvbiIsImFjciI6IjEifQlsngS6CL5HQINntqJxldeScr8mYI9ULra3rqm4Y3s1XbJpEpEMEi8PFju3jqHtOMkxxHceh1AxjZn-o3IDkqefsKtUdxQpNY_nCoUw36kTaCC9osCz3qgbcELT24ZJUOgZYRzx9fqaLT0zoX1f28ZSSLvxkLuKm86h3mCAQSNbAxvsjeXL9zwEUsc1ESJDJDg90RAwPd2h5Gx5zMhrH8JRt5hNu6PzH-GNfLs2FOfeWXGppvqxx5jMf7W-9MiY4nkbPMMmY_hbbQnNLy75Jq_-zLqLZ7fR-XMfVXP8d0OEffYjCHiszpKetBxTj8HbysglBJ8pCMefEMPQaUOBbYlA
That’s a huge mess of characters.  What I would highlight are the two periods present in the string.  It’s possible to decode the whole string and see what is in it, but today we’re only interested in seeing the claims.  The claims are the part between the second and third periods.  Once we pull that out, we can decode it.  It’s a little interesting decoding this because it is Base 64 URL encoded and when you decode it, you don’t want to decode to UTF8 but to ASCII instead.  Once you’ve done so, the claims look like this:
"aud":"http://win8webapp.azurewebsites.net/",
"iss":"https://sts.windows.net/ef86b20c-7782-473e-945f-583b88eb735b/",
"iat":1379607257,
"nbf":1379607257,
"exp":1379636057,
"ver":"1.0",
"tid":"ef86b20c-7782-473e-945f-583b88eb735b",
"oid":"39e6fb4c-36f5-4d67-bf4f-19816b19f99c",
"upn":"[email protected]",
"unique_name":"[email protected]",
"sub":"72zTkOogCTBxwffHCm4oM9dQNWq4ecSo75JP97wiVlA",
"family_name":"user",
"given_name":"user",
"appid":"fa94de18-3636-447e-8986-99db18aeac85",
"appidacr":"0",
"scp":"user_impersonation",
"acr":"1"
This identifies who I am as a user but also specifies other things like which app I have access to, what type of permission it is, and more.  We could use this data with the Graph Explorer API to get further information but we’ll leave that for another day. 

Next Steps

At this point we have a web application that requires Active Directory authentication and permissions in order to use.  More importantly, we have iOS and Android client applications that are capable of authenticating a user with our own Windows Azure Active Directory account and then accessing resources secured by it!  This opens up a ton of scenarios, especially for enterprises that want to enable Bring Your own Device but still secure their assets.  A few things which I haven’t covered today (and may go into in the future, especially if I hear people ask for it) are:

  • There isn't any error handling in this example. We'd certainly want to handle any issues if there were any.
  • Caching the Access Token / access information in case of app relaunch
  • Getting a new Access Token after expiration using the Refresh Token
  • Setting up a secured web resource (I’m pointing to a different tutorial above which works but could be better)
  • Wrapping all of the above functionality into a library you could just drop into your iOS / Android project
  • Making requests to the Graph Explorer API to get more information on your claims.
  • Explaining how you can sync your on-premise AD account with your Windows Azure one
  • Providing more specific steps about pushing the web app to Windows Azure Web Sites.

Clearly there is a ton more we can do to simplify authenticating with AD and accessing secured resources from different device platforms and my hope is that in the future, you’ll see this become much easier and much more accessible.  Let me know if you have questions, run into issues, or anything else in the comments.


Chris Risner


Leave a Comment