Continuing where we left off in the previous post, we’ve got all the tools, so the next step is setting up the authentication itself. You probably don’t want to make a mess of the working state of your actual application. Or perhaps you don’t yet have an application to test with. For this walkthrough, you can start with a new ASP.NET MVC 4 project from Visual Studio and select Internet Application as the template. The template contains a layout that displays the current logged-in user, which demonstrates that the authentication mechanism integrates nicely with the rest of ASP.NET. After you’ve got your application open in Visual Studio, right-click on the project in Solution Explorer and select Enable Windows Azure Authentication.
Clicking on the menu item opens up a dialog that asks for your tenant domain name.
That is, unless it throws you a COMException instead. If that happens, ensure that you’ve got an IIS or IIS Express virtual directory set up for your web application. Visual Studio doesn’t let you misconfigure the virtual directory settings like this, but it might still happen if you’re running your web app as an Azure Web Role in the Compute Emulator.
Once you type in your tenant domain name, you’ll be prompted to log in. Log in with an account that has administrative access (for example, the account you created during the tenant setup process).
The prompt uses IE, so if you happen to be logged in an IE session with a Microsoft Online account that doesn’t exist in the tenant domain, you might end up with an error instead. This happens to me quite often, because I use our Office 365 apps with IE.
The easiest way to get rid of this error is to cancel the WAAD authentication setup, open up the Visual Studio web browser (View –> Other Windows –> Web Browser) and use it to navigate to the Microsoft Online logout page. Once the logout process is complete, close the Visual Studio web browser and try the WAAD authentication setup again. At this point, if everything went well, you’ll be presented with a happy green check mark.
You’ll have a number of changes in your Web.config, mostly under system.identitymodel:
The default authentication module for ASP.NET applications is the Forms Authentication module. You can only use a single authentication module for your application, and since the Forms Authentication module is configured at the web server level, it takes precedence. So make sure that your application doesn’t use the Forms Authentication module by adding this under system.webServer/modules:
<remove name="FormsAuthentication" />
A brief interlude on WAAD Single Sign-On
Before we go further, a few words on how SSO actually works. When a request comes in to your web application, the authentication module checks to see if the user is authenticated or not. This is typically done by looking at a cookie that holds some sort of authentication ticket. If the user is authenticated, then it’s all good. However, if the user is not authenticated, a bunch of things have to happen. First, the authentication module redirects the user’s browser to the identity provider. Among the information it passes on is a return address. Since the login process happens in the user’s browser, we can’t really control it. In order for things to work smoothly, we need to tell the identity provider what to do after the user has logged in. A return address tells the provider where the user should be redirected once authentication is completed. After the user logs in, the identity provider uses the return address combined with a login token to redirect back to our application. Our application invokes the authentication module, which takes the login token, verifies its validity and extracts the user’s identity. This is the point where the user is finally authenticated with our application.
I won’t pretend I understand all or even most of the security implications here, but one consideration is definitely this: you can’t let just anyone authenticate users against your directory, even if the only data you’d pass on to them would be the user name. Imagine a rogue third party that created an app that had your company’s branding and used your company’s official authentication mechanism – and then tricked your users into giving them confidential data. That’s no good, so we need to control who we give the login token out to. Which is what we’ll do next.
Configuring the Service Principal
Before your application can use WAAD authentication, it must be registered in WAAD. This registration is called a Service Principal, and a big part of what the Visual Studio wizard did for you involved creating the Service Principal. One of the things configured in the Service Principal settings is the list of accepted after-login return addresses. The wizard creates a Service Principal with a single return address: https://localhost:44302 — the port number is arbitrarily assigned, so yours might not be exactly the same. It also enables SSL for your app, so the return address will work. This is all well and good, unless your web application can’t run in that particular port – such as with Azure Web Roles in the Compute Emulator. That means you won’t get the login token from WAAD unless we add a new return address. Fire up Microsoft Online Services Module for PowerShell again. Call
Connect-MsolService to authenticate, type
Get-MsolService and hit tab. PowerShell will expand this to
Get-MsolServicePrincipal. Hit enter… and boom! “Get-MsolServicePrincipal : The term ‘Get-MsolServicePrincipal’ is not recognized as the name of a cmdlet, function, script file, or operable program.”
Wait… what? Yeah. So PowerShell’s autocomplete suggests that there is a commandlet with this name, but then it’s not there when you try to use it. This is a weird artifact of the way the commandlets are packaged. What you now want to do is run
Import-Module MSOnlineExtended –Force, and then the command will work. The
–Force flag is necessary, because the extended module lives in the same binary file as the regular one, and without it, PowerShell will think it’s already well and properly loaded. In order to configure the return addresses, we need a handle on the service principal created by the Visual Studio Wizard. In the MSOL PowerShell window, type
Get-MsolServicePrincipal | select AppPrincipalId,DisplayName
PS C:\Windows\system32> Get-MsolServicePrincipal | select DisplayName,ObjectId
My test app 3dc125e6-d518-40d2-9392-87a03dac8f68
The last principal in the list is the one the wizard generated for you. Visual Studio always registers your application as “My test app”, regardless of what your app is actually called – for instance, the name of my application is the far more sensible “WAADDemo”. In my example, the generated principal’s object id is
3dc125e6-d518-40d2-9392-87a03dac8f68. In order to get a handle on that particular principal, we can run
$principal = Get-MsolServicePrincipal -ObjectId 3dc125e6-d518-40d2-9392-87a03dac8f68
To list the configured reply addresses, we type:
$principal.Addresses | select Address,AddressType
and get a return address listing
PS C:\Windows\system32> $principal.Addresses | select Address,AddressType
To add the final deployment and Compute Emulator reply addresses, we modify the address list we just got, then set it back to the principal:
$addresses = $principal.Addresses
$addresses.Add((New-MsolServicePrincipalAddresses -Address http://localhost:81))
$addresses.Add((New-MsolServicePrincipalAddresses -Address http://my-app.example.com))
Set-MsolServicePrincipal –ObjectId 3dc125e6-d518-40d2-9392-87a03dac8f68 -Addresses $addresses `
-DisplayName "WAADDemo App"
The first line gets the current address list to a new variable. The next two lines create the address objects and add them to the list. The final command associates the updated address list with the principal and changes its name to “WAADDemo App” for good measure.
The last thing you need to do is ensure that you’re sending the correct reply address to WAAD. Edit web.config at system.identityModel.services/federationConfiguration/wsFederation and replace the value of the reply attribute with one of the reply addresses you configured in the previous step:
<wsFederation passiveRedirectEnabled="true" issuer="https://accounts.accesscontrol.windows.net/a071bf68-ee1d-46aa-ac6d-cfddf3826050/v2/wsfederation" realm="spn:e8a3050f-0c61-46bd-9808-ff7dd5dcdb4b@a071bf68-ee1d-46aa-ac6d-cfddf3826050" reply="http://localhost:81/" requireHttps="false" />
By now, when you run the application, you should be automatically redirected to the Windows Azure Authentication portal:
When you log in, you’ll be redirected back to your app as an authenticated user:
If you play with the app a bit, you’ll notice that logging out doesn’t actually work. That’s a quirk of Azure federated login – you can visit the logout URL if you like, but it won’t really take effect unless you close the browser session. Phew, that was a lot of stuff to go through! What’s interesting here is that you didn’t have to write a single line of C# code. Now, that in itself is not really a goal worth pursuing, particularly if it results in an ungodly mess of XML configuration. However, what is remarkable and desirable is that once you understand all this, setting up new applications that share the same credentials is actually a breeze. So there is a point to all this, believe it or not. Next up: User details! We’ll be reading group memberships using the Graph API.