Using Active Directory Federation Services to Authenticate / Authorize Node.js Apps in Windows Azure

It’s gotten easy to publish web applications to the cloud, but the last thing you want to do is establish unique authentication schemes for each one. At some point, your users will be stuck with a mountain of passwords, or, end up reusing passwords everywhere. Not good. Instead, what about extending your existing corporate identity directory to the cloud for all applications to use? Fortunately, Microsoft Active Directory can be extended to support authentication/authorization for web applications deployed in ANY cloud platform. In this post, I’ll show you how to configure Active Directory Federation Services (ADFS) to authenticate the users of a Node.js application hosted in Windows Azure Web Sites and deployed via Dropbox.

[Note: I was going to also show how to do this with an ASP.NET application since the new “Identity and Access” tools in Visual Studio 2012 make it really easy to use AD FS to authenticate users. However because of the passive authentication scheme Windows Identity Foundation uses in this scenario, the ASP.NET application has to be secured by SSL/TLS. Windows Azure Web Sites doesn’t support HTTPS (yet), and getting HTTPS working in Windows Azure Cloud Services isn’t trivial. So, we’ll save that walkthrough for another day.]

2013.04.17adfs03

Configuring Active Directory Federation Services for our application

First off, I created a server that had DNS services and Active Directory installed. This server sits in the Tier 3 cloud and I used our orchestration engine to quickly build up a box with all the required services. Check out this KB article I wrote for Tier 3 on setting up an Active Directory and AD FS server from scratch.

2013.04.17adfs01

AD FS is a service that supports identity federation and supports industry standards like SAML for authenticating users. It returns claims about the authenticated user. In AD FS, you’ve got endpoints that define which inbound authentication schemes are supported (like WS-Trust or SAML),  certificates for signing tokens and securing transmissions, and relying parties which represent the endpoints that AD FS has a trust relationship with.

2013.04.17adfs02

In our case, I needed to enabled an active endpoint for my Node.js application to authenticate against, and one new relying party. First, I created a new relying party that referenced the yet-to-be-created URL of my Azure-hosted web site. In the animation below, see the simple steps I followed to create it. Note that because I’m doing active (vs. passive) authentication, there’s no endpoint to redirect to, and very few overall required settings.

2013.04.17adfs04

With the relying party finished, I could now add the claim rules. These tell AD FS what claims about the authenticated user to send back to the caller.

2013.04.17adfs05

At this point, AD FS was fully configured and able to authenticate my remote application. The final thing to do was enable the appropriate authentication endpoint. By default, the password-based WS-Trust endpoint is disabled, so I flipped it on so that I could pass username+password credentials to AD FS and authenticate a user.

2013.04.17adfs06

Connecting a Node.js application to AD FS

Next, I used the JetBrains WebStorm IDE to build a Node.js application based on the Express framework. This simple application takes in a set of user credentials, and attempts to authenticate those credentials against AD FS. If successful, the application displays all the Active Directory Groups that the user belongs to. This information could be used to provide a unique application experience based on the role of the user. The initial page of the web application takes in the user’s credentials.

div.content
        h1= title
        form(action='/profile', method='POST')
              table
                  tr
                    td
                        label(for='user') User
                    td
                        input(id='user', type='text', name='user')
                  tr
                    td
                        label(for='password') Password
                    td
                        input(id='password', type='password', name='password')
                  tr
                    td(colspan=2)
                        input(type='submit', value='Log In')

This page posts to a Node.js route (controller) that is responsible passing those credentials to AD FS. How do we talk to AD FS through the WS-Trust format? Fortunately, Leandro Boffi wrote up a simple Node.js module that does just that. I grabbed the wstrust-client module and added it to my Node.js project. The WS-Trust authentication response comes back as XML, so I also added a Node.js module to convert XML to JSON for easier parsing. My route code looked like this:

//for XML parsing
var xml2js = require('xml2js');
var https = require('https');
//to process WS-Trust requests
var trustClient = require('wstrust-client');

exports.details = function(req, res){

    var userName = req.body.user;
    var userPassword = req.body.password;

    //call endpoint, and pass in values
    trustClient.requestSecurityToken({
        scope: 'http://seroternodeadfs.azurewebsites.net',
        username: userName,
        password: userPassword,
        endpoint: 'https://[AD FS server IP address]/adfs/services/trust/13/UsernameMixed'
    }, function (rstr) {

        // Access the token
        var rawToken = rstr.token;
        console.log('raw: ' + rawToken);

        //convert to json
        var parser = new xml2js.Parser;
        parser.parseString(rawToken, function(err, result){
            //grab "user" object
            var user = result.Assertion.AttributeStatement[0].Attribute[0].AttributeValue[0];
            //get all "roles"
            var roles = result.Assertion.AttributeStatement[0].Attribute[1].AttributeValue;
            console.log(user);
            console.log(roles);

            //render the page and pass in the user and roles values
            res.render('profile', {title: 'User Profile', username: user, userroles: roles});
        });
    }, function (error) {

        // Error Callback
        console.log(error)
    });
};

See that I’m providing a “scope” (which maps to the relying party identifier), an endpoint (which is the public location of my AD FS server), and the user-provided credentials to the WS-Trust module. I then parse the results to grab the friendly name and roles of the authenticated user. Finally, the “profile” page takes the values that it’s given and renders the information.

div.content
        h1 #{title} for #{username}
        br
        div
            div.roleheading User Roles
            ul
                each userrole in userroles
                    li= userrole

My application was complete and ready for deployment to Windows Azure.

Publishing the Node.js application to Windows Azure

Windows Azure Web Sites offer a really nice and easy way to host applications written in a variety of languages. It also supports a variety of ways to push code, including Git, GitHub, Team Foundation Service, Codeplex, and Dropbox. For simplicity sake (and because I hadn’t tried it yet), I chose to deploy via Dropbox.

However, first I had to create my Windows Azure Web Site. I made sure to use the same name that I had specified in my AD FS relying party.

2013.04.17adfs07

Once the Web Site is set up (which takes only a few seconds), I could connect it to a source control repository.

2013.04.17adfs08

After a couple moments, a new folder hierarchy appeared in my Dropbox.

2013.04.17adfs09

I copied all the Node.js application source files into this folder. I then returned to the Windows Azure Management Portal and chose to Sync my Dropbox folder with my Windows Azure Web Site.

2013.04.17adfs10

Right away it starts synchronizing the application files. Windows Azure does a nice job of tracking my deployments and showing the progress.

2013.04.17adfs11

In about a minute, my application was uploaded and ready to test.

Testing the application

The whole point of this application is to authenticate a user and return their Active Directory role collection. I created a “Richard Seroter” user in my Active Directory and put that user in a few different Active Directory Groups.

2013.04.17adfs12

I then browsed to my Windows Azure Website URL and was presented with my Node.js application interface.

2013.04.17adfs13

I plugged in my credentials and was immediately presented with the list of corresponding Active Directory user group membership information.

2013.04.17adfs14

Summary

That was fun. AD FS is a fantastic way to extend your on-premises directory to applications hosted outside of your corporate network. In this case, we saw how to create  Node.js application that authenticated users against AD FS. While I deployed this sample application to Windows Azure Web Sites, I could have deployed this to ANY cloud that supports Node.js. Imagine having applications written in virtually any language, and hosted in any cloud, all using a single authentication endpoint. Powerful stuff!

About these ads


Categories: Cloud, Node.js, Tier 3 Enterprise Cloud Platform, Windows Azure

5 replies

  1. I haven’t even read your content yet but I have to say, I’m pretty impressed that you use GIFs instead of JPGs so you can animate some of the steps. Kudos to you sir!

Trackbacks

  1. Windows Azure Community News Roundup (Edition #63) - Windows Azure - Site Home - MSDN Blogs
  2. Active Directory (ADFS) to Authenticate Node.js Apps in MS Azure
  3. Windows Azure 社区新闻综述(#63 版) - 微软云计算: Windows Azure 中文博客 - Site Home - MSDN Blogs
  4. How to Publish Node.js Application to Windows Azure Cloud

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 240 other followers

%d bloggers like this: