In all fairness, this post relates to Azure Service Bus in general and not specifically to Windows Azure BizTalk Services (WABS).

When is this relevant?

Azure Service Bus and WABS both rely on Azure Access Control Service (ACS) to authenticate users before calling the service. This type of authentication is often referred to as Federated Security. In most samples of how to interact with Service Bus or WABS, the client first calls ACS (using user name and password) to receive a token, which is later used upon calling the actual service.

 

Using a ACS Service Identity (service user) makes sense when the client is a system, where you’d probably let each system have its own Service Identity.

-But what if the client is a user, such an employee or customer, perhaps calling in from a mobile unit?

In such cases, you’d have to keep the Service Identity stored on the device/application. Part from the security problems related to some evil person hacking the (Android) phone and then uses the credentials for evil purposes, you can’t do Authorization as every user is using the same credentials.

In such cases, you’d probably want to use some other directory than the one provided in ACS. In most cases Active Directory is likely to be the preferred choice. 

Authentication

Token Based Authentication can be a bit hard to understand, so I’ll try to explain it using an analogy.

Imagine you’re going on a vacation to a different country, and upon facing the scary customs officer, you smile and give him your VISA card. Take my word for it, it won’t work, but the interesting part is why. Despite the anger he or she will direct towards you, i’s not about you at all. In fact, they will never trust YOU!

-The problem is that they don’t trust the VISA organization to vouch for your identity.

So we need to go to a trusted authority and ask them to vouch for our identity, in Sweden that would be the local police department. They won’t trust you either, and will ask for some other proof, but more on that later. Let’s just assume all goes well and they’ll issue you a passport. 

The passport holds information about you, some information is public others may be hidden or encrypted, but more importantly it is signed by a trusted authority.

With a passport in our hand, the officer now trust your identity (Authentication), and he will now proceed to check your criminal records and ask a bunch of questions to determine if he will allow you to enter the country (Authorization).

Leaving the analogy and getting back to Federated Security. It’s pretty much the same thing. The Swedish Police department plays the role of the Issuer (ACS) the customs officer plays the role of the Relying Party Application (WABS or Service Bus), and the passport is of course the Token.

The difference between the analogy and Service Bus authentication, is that while the customs trust many different issuers, Windows Azure Service Bus ONLY TRUST ACS!

However, ACS can be configured to trust other issuers also referred to as Identity Providers. If we go back to the analogy, and the local Police department that issued the passport, -why did he trust you? There are actually a number of ways to prove your identity, but lets assume you’d use an ID. This is sometime referred to as a chain of trust.

This is how Active Directory come in play. Active Directory can be configured with Active Directory Federated Services (ADFS). ADFS is an issuer, and although Service Bus does not trust your ADFS, ACS can be trusted to do.

By adding your ADFS as an Identity Provider in ACS, you can authenticate yourself with ACS using a token provided by ADFS! ACS will then provide you with a new token which can be used to authenticate yourself with Service Bus.

Step 1: Ask ADFS to issue a token for ACS using Active Directory user name and password.

Step 2: Ask ACS to issue a token for SB, using a token issued by ADFS

Step 3: Call the service using the token provided by ACS.

Authorization

Although it won’t be sufficient for us, it’s worth pointing out that ACS provides some level of authorization which you can read more about here. ACS can however not provide authorization based on AD group membership, as the group membership claim comes as a comma separated string, with all groups:

Eg: CN=Sales,CN=Employees,,,,,,,,CN=Users,DC=MyDomain,DC=net

Before we dive into BizTalk Services I’d like to point out a couple “issues” you might encounter. In the case where your service is a REST service (such as with WABS), you’ll face two problems, one small and one big. Both problems relates to the fact that Service Bus will remove your token after the token has been verified by Service Bus. In other words, the token is not for you!

This little problem can be worked around, by adding the token twice. One using the “Authorization” header, and the other using a custom header.

The potentially bigger issue relates to the HTTP header it self, or rather its size. Using IIS 7 that limit is 16KB, but might differ depending on the version of IIS. By propagating the group membership claims from ADFS to the token issued by ACS, the token can get pretty big (depending of the number of groups the user is a member of). Adding the token twice, and you might pass the limit. The good news is that this limit is configurable, but the problem can be difficult to identify, as it might not occur for all users.

Anyway, by adding the token twice we can now evaluate group membership and authorize the user within our service (SB) or itinerary (WABS).

The Setup

The setup involves many steps, some of witch I’ll assume you have already done. For instance, it’s outside the scope of this post to set up ADFS and install the WABS SDK.

1. The Itinerary

As the overall sample is complicated enough, we’ll stick with a very simple itinerary .

The itinerary received the message using a One-Way bridge, and routs the message to either one of the queues, depending on if the user is part of any of the groups.

2. Extracting the HTTP Custom Header

As described earlier, we need to add the token twice. Once for the Service Bus to do Authentication, and the other for us to do Authorization. To do this, double-click the One-Way bridge to open the bridge configuration.

Select any of the two Enrish stages, and click the Property Definition in the Property Window. Add a new property definition, and set the values as following:

I will call my custom header “AUTH”, if you care to use a different name, just change the Identifier to what ever work for you.

3. Create a Message Inspector

Now that we have the token, we need to extract the group claim. To do this we’ll need to create a Message Inspector. 

Follow these steps to create your project:http://msdn.microsoft.com/en-us/library/windowsazure/dn232389.aspx

Here is the code I used:

public class AuthorizationInspector : IMessageInspector 
{
    const string GROUPCLAIM = "http://schemas.xmlsoap.org/claims/Group";

    /// <summary>
    /// The name of the custom HTTP header, Eg. "AUTH"
    /// </summary>
    [PipelinePropertyAttribute(Name = "AuthToken")]
    public string AuthToken { get; set; }
    /// <summary>
    /// A comma separated list of authorized groups, Eg. Sales, Marketing 
    /// </summary>
    [PipelinePropertyAttribute(Name = "InGroups")]
    public string InGroups { get; set; }
        
    /// <summary>
    /// Processesing the Message
    /// </summary>
    /// <param name="message"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public Task Execute(IMessage message, IMessageInspectorContext context)
    {
        bool isInGroup;
        try
        {
            // Get the incomming SWT token
            var token = message.GetPromotedProperty(AuthToken);

            if (token == null)
                throw new Exception(AuthToken + " token is null");

            var requestedGroups = InGroups.Split(',');
            var claims = GetClaims(token.ToString());
                
            var groups = (from c in claims[GROUPCLAIM].Split(',')
                            select new GroupEntry(c)).Where(g => g.Type == "CN");

            var isingroup = groups.Where(g => requestedGroups.Count(r => r == g.Name) > 0);

            return Task.Factory.StartNew(() =>
            {
                message.Promote("IsInGroup", isingroup.Count() > 0);
            });

        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}

* The GetClaims method and the GroupEntry class is part of the downloadable sample

Compile your project. and go back to your Bridge configuration. Select the Enrich stage again (outer rim) and click the On Exit Inspector in the property window.

Type the FQN of your Inspector class in the Type field, Eg:

InspectorsLibrary.AuthorizationInspector, InspectorsLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a1cd373975c6a197

 

 

Our newly created Inspector had two properties:

  • AuthToken – The name of the custom token we’ll use
  • InGroups – The authorized groups Eg: Sales,Marketing,Finance

Build and deploy your bridge.

4. Configure ADFS to issue tokens for ACS

Open the Azure Management Portal, and browse to the Active directory. Select the namespace you’re using for WABS, and select Manage to open the ACS portal. At the bottom of the navigation field, click Application Integration, and copy the WS-Federation Metadata URI. This file includes the Realm(s) of the ACS along with public keys etc, needed to configure the Relying Party Trust in ADFS.

Next open the ADFS Manager, and browse to the Relying Party Trust node. Right click the node and select Add Relying Party Trust and click the Start button.

Keep the “Import data about” option, and paste in the ACS WS-Federation Metadata URI. Click Next *4 and Finish (leave the checkbox to open the claims configuration).

In the Edit Rule dialog, click Add Rule, and Next. Give it a name and set the Attribute Store to Active Directory.

Select the “Is-Member-Of-DL” attribute and map it to the Groups claim.

Click Ok.

In the ADFS Manager, browse to the “Endpoints” node. Make sure the usernamemixed endpoint is enabled. Also make a note of the URI together with the FederationMetadata URI.

5. Adding ADFS Identity Provider in ACS

Go back to the ACS portal, and click Identity Providers. Click Add and select WS-Federation identity provider and Next.

Give it a name and set the login text (although will never use it). Paste or type the URI to the ADFS FederationMetadata. I ran into some problems here, and needed to copy it locally, and add it using the Browse option. This file includes all configured claims from ADFS (among many other things). 

In the Used By section, deselect all applications but your WABS application.

To propagate claims from the ADFS token to the ACS token, we need to do one more step. Click the Relying Party Application node, and select your WABS application. At the bottom of the page, click the selected Rule Group. Click the Generate button, and select your new Identity Provider. Click Save.

6. Try it out!

Kudos to you if you made it this far!

If you download the sample, you’ll find the MessageSender project which I originally got from here. I’ve made some modifications to make it work with ADFS. It generally comes down to two methods at the end of the MessageSender class.

  • RequestSamlToken – Uses a WSTrust channel to get the SAML token from ADFS.
  • RequestSwtWithSamlToken – Similar to the GetAcsToken method, but uses assertion to pass along the SAML token rather then username/password as with the GetAcsToken.

 

Related links:

Federated Authentication for Azure Service Bus

Azure Service Bus

BizTalk Services

Blog Post by: wmmihaa