Securing and authenticating azure service bus relay messages using a shared secret

In this post I’ll cover how to secure an on premise WCF relay service using the Windows Azure Access Control Service (ACS) as a relying party and a shared secret. The same shared secret is known by both the service and calling application. This is by no means the only way to secure your on premise service but its relatively easy to implement once you figure out how to programmatically request a WRAP token from the ACS.

In my case the client is an ASP.NET MVC website running on Windows Azure and the on premise service is exposing JSON through a WebHttpRelayBinding.

IMG_1097

The Service Bus and Access Control have a “special relationship” with each other in that each Service Bus service namespace is paired with a matching Access Control service namespace of the same name but suffixed with “–sb”. The reason for this special relationship is in the way that Service Bus and Access Control manage their mutual trust relationship and the associated cryptographic secrets.

When you create a new namespace using the portal a secret key is automatically generated for you and this secret key is known to the ACS. Pick your namespace and click  on “access key” to see the details

SB

Specify the shared secret in the transportClientEndpointBehavior section of the app.config file and your WCF service is now authenticated with the ACS when the relay service is established.

      <endpointBehaviors>
        <behavior name="sharedSecretClientCredentials">
          <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
          <transportClientEndpointBehavior credentialType="SharedSecret">
            <clientCredentials>
              <sharedSecret issuerName="owner" issuerSecret="NW1ie7/nlhggTFnB5L7nDBrOLC+o1E1P4ZZqPaP2mY4=" />
            </clientCredentials>
          </transportClientEndpointBehavior>
        </behavior>
      </endpointBehaviors>

Here’s the snippet to configure the shared secret for the caller.

<webHttpRelayBinding>
        <binding name="default">
          <security relayClientAuthenticationType="RelayAccessToken" />
        </binding>
      </webHttpRelayBinding>

Now on to the interesting part, how to programmatically get a rely access token from the ASP.NET MVC consumer. The trick here is to know that the ACS endpoint takes the format “https” + serviceNamespace + “-sb.accesscontrol.windows.net/WRAPv0.9″. I’ve published  this gist with the code.

using (var serviceRequest = new WebClient())
      {
      string token = GetAuthorizationToken("yourservice","owner", "NW1wr7/nlgggTFnB5L7nDBrOLC+o1E1P4ZZqPaP2mY4=");
      serviceRequest.Headers["Authorization"] = string.Format("WRAP access_token=\"{0}\"", token);
      string response = serviceRequest.DownloadString(new Uri(url));
      return response;
    }
 
 
// connects to ACS and gets WRAP Authorization token
 
public string GetAuthorizationToken(string serviceNamespace, string issuerName, string issuerPassword)
        {
            string acsEndpoint = "https://" + serviceNamespace + "-sb.accesscontrol.windows.net/WRAPv0.9";
            string relyingPartyAddress = "http://" + serviceNamespace + ".servicebus.windows.net";
 
            NameValueCollection postData = new NameValueCollection
            {
                { "wrap_scope", relyingPartyAddress },
                { "wrap_name", issuerName },
                { "wrap_password", issuerPassword },
            };
 
            WebClient webClient = new WebClient();
            byte[] responseBuffer = webClient.UploadValues(acsEndpoint, "POST", postData);
            string response = Encoding.UTF8.GetString(responseBuffer);
 
            string encodedtoken = response.Split('&')
                .Single(value => value.StartsWith("wrap_access_token="))
                .Split('=')[1];
 
            string token = System.Web.HttpUtility.UrlDecode(encodedtoken);
            
            return token;
        }

The message format to request a token from the ACS is explained here.

If you plan on making multiple calls you should consider caching the token, its time to live is 1200 seconds. Finally pass the token in a custom Authorization header and you are done and dusted !

may the source be with you !

Aidan

About these ads

One thought on “Securing and authenticating azure service bus relay messages using a shared secret

  1. Pingback: Azure Service Bus authentication and federation | Stephen Hirst

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