Friday, 15 June 2012

Handling SWT Tokens from ACS (Part Two)

The full code from this blog is now available on GitHub as a reference implementation.

In Part One of this series of blogs I showed you how to set up Windows Azure's ACS to provide SWT tokens to a client over OAuth WRAP using a Service Identity. In this post I'll show you how you can parse and validate this token.

Parsing the token

At the end of Part One we successfully got token back from ACS using a WebClient. The raw response looked similar to this:

wrap_access_token=http%253a%252f%252fschemas.xmlsoap.org%252fws%252f2005%252f05%252fidentity%252fclaims%252fnameidentifier%3dRESTClient%26http%253a%252f%252fschemas.microsoft.com%252faccesscontrolservice%252f2010%252f07%252fclaims%252fidentityprovider%3dhttps%253a%252f%252ftwo10na.accesscontrol.windows.net%252f%26Audience%3dhttp%253a%252f%252flocalhost%253a50865%252f%26ExpiresOn%3d1339758203%26Issuer%3dhttps%253a%252f%252ftwo10na.accesscontrol.windows.net%252f%26HMACSHA256%3dF4DOJezHyjMpNiC%252fC1vFSS3v3ITFcy6SXyGoT1Zv8ZI%253d&wrap_access_token_expires_in=600

We then URL decoded the response and split out the actual content to get a token like this:

http%3a%2f%2fschemas.xmlsoap.org%2fws%2f2005%2f05%2fidentity%2fclaims%2fnameidentifier=RESTClient&http%3a%2f%2fschemas.microsoft.com%2faccesscontrolservice%2f2010%2f07%2fclaims%2fidentityprovider=https%3a%2f%2ftwo10na.accesscontrol.windows.net%2f&Audience=http%3a%2f%2flocalhost%3a50865%2f&ExpiresOn=1339758203&Issuer=https%3a%2f%2ftwo10na.accesscontrol.windows.net%2f&HMACSHA256=F4DOJezHyjMpNiC%2fC1vFSS3v3ITFcy6SXyGoT1Zv8ZI%3d

This MSDN page gives us the anatomy of a SWT token from ACS. It is essentially a set of key/value pairs separated by the ampersand ('&') character. The keys and values are separated by the equals ('=') character. We also learn that our token contains four mandatory parameters:

  • Issuer
  • Audience
  • ExpiresOn
  • HMACSHA256.

It will also contain any claims we have configured ACS to send us as more key/value pairs. If the claim contains more than one value they will be separated by the comma (',') character.
With this knowledge we are able to dissect the token. Notice that each individual parameter is also URL encoded.
 
Now that we have each parameter as a variable we can validate the token and process it's claims. We can encapsulate the data we have parsed into a class like this. Notice that the expiresOn parameter is in Unix time so we need to calculate the seconds since the epoch to get a DateTime object.

Validating the token

There are four things we should probably validate to ensure our token is authentic.
  1. Has the token expired?
  2. Is the signature valid?
  3. Do we trust the issuer?
  4. Are we the expected audience?
Let's add a static Validate method to the SimpleWebToken class to do this:

Validating expiry, issuer and audience is very simple to do but checking the signature is more difficult. I've added three more methods to help do this.

To validate the signature we need to generate a new signature using a trusted signing key. If this signature matches the issued signature in the token then we know that they were both generated using the same key, and therefore we can trust that the token was issued from where we think it was. This also gives us some guarantees that the token hasn't been tampered with over the wire.

StringToSign reconstructs the token and gives us the parts that we need to include in the hash. ComputeSignature creates the hash using a given signing key and CheckSignature compares the computed signature with the issued one.

By calling the Validate method we are able to determine the authenticity of an SWT token.The next step will be to use these utilities in a Relying Party and authenticate/authorise a client presenting this token. This will be covered in Part Three.

Tuesday, 15 May 2012

ACS Rule Groups and Service Identities

In my previous post I walked you through configuring ACS to issue SWT tokens to a client using Service Identities and when it came to configuring the Rule Groups we just left everything as default. I just wanted to expand on this area a little bit as the Rule Group can be very useful when it comes to securing a Relying Party with a Service Identity.

Restricting access

By accepting the defaults when creating the rule group we are essentially telling ACS that we accept ANY Service Identity credentials as valid for the relying party and to just pass on the claims that ACS produces. But what if we want to restrict which Service Identities can authenticate with ACS? Well it's actually very simple, we modify the rule!


By selecting an Input claim type of nameidentifier we are able to instruct ACS to only run this rule when a matching claim and value is found. When authenticating with a Service Identity, ACS will create a nameidentifier claim with the value set to the Service Identity name. We can specify this as our claim value in this rule.

The rule then tells ACS to output the same nameidentifier claim with the same value, effectively passing it through. Of course we could set this up to output a completely different claim and value but for now this is all we need to do. The output claim will then be wrapped up into the SWT token and sent back to the client.

This rule effectively restricts access to the relying party by only accepting the Service Identity matching the claim value.

I can test this by trying to authenticate with the 'RESTClient' service identity which should succeed based on my rule and then using the 'two10na' Service Identity which should fail.

First using 'RESTClient'



This results in a successful response:


Now let's try it using 'two10na':



Access denied! We get a 403 (forbidden) back from ACS because it is unable to successfully run the Rule Group associated with the Relying Party.

Handling SWT Tokens from ACS (Part One)

The full code from this blog is now available on GitHub as a reference implementation.

If you are developing an application that requires claims-based authentication then Windows Azure ACS (Access Control Service) could be the answer to your prayers. ACS can be used as an out-of-the-box STS in this scenario, although this is actually just one small part of its full offering.

If you are committed to using WCF with WS-Federation then your obvious choice will be to setup ACS to provide SAML tokens over it's WS-Federation binding. This is a well documented subject so will not be covered here. But what if your application can't use WCF or you choose not to use WCF? Is ACS still useful to you? Well the answer is yes it is as it comes with an array of other integration options such as OAuth2 and OAuth WRAP. Using these protocols we can request SWT tokens to provide our claims and the aim of this post is to show you how you can do this without using WCF at all.

Configuring ACS

So here's the scenario. You're building a RESTful API and you want to authorise calls to it using claims. ACS can help accelerate the process here as it can be our trusted token provider.

For this demo we'll be using a Service Identity to authenticate with ACS. Service Identities are useful for authenticating applications rather than users as they simply provide a method for an application to pass credentials to the ACS without needing to prompt the user and receive a token back for presentation to the relying party (in this case our REST service).

You can configure Service Identities in ACS on this screen:
ACS Service Identities management

Add the Service Identity

First we need to Add the Service Identity:

Add Service Identity
Give the Service Identity a name, description and select Password for Credential Type. You can also give the credential an Effective date, if we want it activate at a specific time and also an Expiration date at which point the credential will no longer be active. It's very important to remember that credentials expire so make sure you reset this value if you want to continue using it! Alternatively add a new credential to the Service Identity.

So we now have a Service Identity and a Password credential associated with it.

Add a Relying Party

We now need to create a Relying Party in ACS that will establish a trust relationship between the REST API and ACS. To do this navigate to 'Relying party applications' in the ACS control panel. You should see this screen:
Relying Party Applications management

From here we can add a new relying party:
Add Relying party
Give the relying party a name and select 'Enter settings manually' under 'Mode'. Now we must ensure that we enter a value for 'Realm' that matches the URL of the REST API. This is vital as the SWT tokens will be validated against this when we come to make API calls.

For our simple scenario we can leave 'Return URL' and 'Error URL' blank.

Select 'SWT' under Token format and leave the lifetime as default.

Add Relying Party (continued)
We don't need to use any Identity providers so uncheck all boxes. Check 'Create new rule group' under 'Rule Groups'.

Under 'Token signing key' click the 'Generate' button to generate a new Symmetric Key for this relying party. This key will be used to sign the tokens issued from ACS, copy and paste this key to notepad for later. You can add/delete/edit these keys within the 'Certificates and keys' section in the portal. 

Note: There is a default Signing Key within ACS that will be used if you do not create one for your RP but it is a security risk to use the same signing key across all RPs.

Configure the Rule Group

We now need to configure the Rule Group for the relying party. Rule groups act like a pipeline for transforming a set of claims into a new set of claims. Navigate to 'Rule groups' in the portal.

Rule groups management
Click on the 'Default Rule Group for <YOUR RELYING PARTY>' that was created for us when we added the relying party. You should now see this screen:
Edit Rule Group
We need to add a claim rule in order to have ACS process our token request successfully so click on 'Add'.

Add Claim Rule
Select 'Access Control Service' as the input claims for this rule will be generated as a result of authenticating with ACS itself via the Service Identity. We can leave all the other fields as default as we only want to pass through the claims generated by ACS back to our client. If you wanted to add some additional claims to your token you could easily do so here by adding more claim rules that take Any input claim / value and outputs the claim type and value you wish to add.

Request a Token from ACS

We have now configured ACS to receive client credentials and issue an SWT token for a given relying party. So lets test that this works by writing some client code to request a token.



We can use System.Net.WebClient to make a simple HTTP POST request to ACS using the WRAP protocol. By navigating to the 'Application integration' section in the portal we will find a list of URLs we can use to request tokens from the ACS.


In our case we are going to use OAuth WRAP so we need the URL highlighted above.

Set client.BaseAddress to your base ACS URL without the "WRAPv0.9" part, we will tell our WebClient to append that bit later.

We then need to set wrap_name to the Service Identity name we configured earlier, wrap_password to the password credential of our Service Identity and wrap_scope to match the Realm of our Relying Party. The call to client.UploadValues("WRAPv0.9", "POST", values) appends "WRAPv0.9" to our base URL, tells the WebClient object to use HTTP POST and adds our wrap parameters as the data.

The response that comes back from the ACS contains our SWT token, success!



In Part Two I will show you how we can now validate this token and use it to authenticate a RESTful API.


Wednesday, 15 February 2012

Who on earth would care about anything I have to say?

Well this is my first blog after resisting the pressure to succumb to the phenomenon that is blogging. I've always thought, "who on earth would care about anything I have to say", in fact I'm 99% sure that no one other than me has read this very message.

So what's the point?

Well as a professional software developer I come across many scenarios which involve researching and prototyping solutions to problems. In the years I have been doing this a lot of this information has been lost to me as I do indeed have a brain like a sieve. It was only after partaking in one of these learning exercises that a colleague suggested to me that I should document what I had achieved in a blog. At first I was resistant but his reasoning was irrefutable, a blog can be like a personal database of tips and tricks that is much easier to query than my frazzled mind.

So here we are, I now have a blog.

p.s. What has really surprised me whilst writing this is the fact that "blog" is NOT in Chrome's spell-checker!