Zulfiqar's weblog

Architecture, security & random .Net

Using WIF for securing REST Service

Posted by zamd on July 31, 2010


OAuth WRAP and SWT (Simple Web Token) have emerged as a standard way for employing claim-based-security to the REST services.  Conceptually this model is very similar to the one used in SOAP world. A client goes to an issuer, authenticates itself using some token and gets back a different token (containing claims) in SWT format. 

WIF provides a rich API and object model to claim-enable your .Net applications but currently it doesn’t natively support OAuth or SWT. In this post, I’ll show how you can extend WIF to bring claim-based-security to REST services.  My goal is to implement this functionality in such a way that all the WIF goodness around claims-transformation (ClaimsAuthenticationManager), claim-based-authorization (ClaimsAuthorizationManager) etc can be used exactly the same way in the REST world.

I have achieved this by introducing an OAuth WRAP channel which sits in the WCF channel stack and perform an almost identical job to its SOAP counterpart WS-Security channel.  I have implemented the OAuth WRAP channel using the interceptor API from the REST Starter Kit.

image WebServiceHost2 host = new WebServiceHost2(typeof(TestService), new Uri(http://localhost:9090));

host.Interceptors.Add(new OAuthWrapSecurityChannel());

host.Open();

The OAuth channel takes care of extracting the token from the incoming message, running it through the validation pipeline (based on WIF SecurityTokenHandler framework), calling ClaimsAuthenticationManager, setting the WCF authorization context so that ClaimsAuthorizationManager can be called, and finally presenting the claims to the service method in the standard WIF way: Thread.CurrentPrincipal :)

Now with OAuth channel plugged in, if I call the service with a token issues by the Windows AppFabric ACS:

clip_image002

I get following output on the service side.

clip_image001

And from the service code, you would notice that standard WIF API is used to access incoming claims.

[WebGet]

string Hello()

{

    Console.WriteLine("Hello called…");

    Console.WriteLine("——————");

    var cp = Thread.CurrentPrincipal as IClaimsPrincipal;

    if (cp != null)

    {

        foreach (var id in cp.Identities)

        {

            Console.WriteLine("Authentication Type: " + id.AuthenticationType);

            Console.WriteLine("Is Authenticated: " + id.IsAuthenticated);

            Console.WriteLine("Name: " + id.Name);

            Console.WriteLine();

            Console.WriteLine("Claims…");

            foreach (var c in id.Claims)

            {

                Console.WriteLine(c.ClaimType + ": " + c.Value);

            }

        }

    }

    return "Hello, World";

}

 

WIF would be configured using exactly same configuration settings required for a SOAP service.

  1. <configuration>
  2.   <configSections>
  3.     <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  4.   </configSections>
  5.  
  6.   <system.serviceModel>
  7.     <behaviors>
  8.       <serviceBehaviors>
  9.         <behavior>
  10.           <federatedServiceHostConfiguration />
  11.           <serviceDebug includeExceptionDetailInFaults="true" />
  12.         </behavior>
  13.       </serviceBehaviors>
  14.     </behaviors>
  15.     <extensions>
  16.       <behaviorExtensions>
  17.         <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  18.       </behaviorExtensions>
  19.     </extensions>
  20.   </system.serviceModel>
  21.   <!–WIF configuration–>
  22.   <microsoft.identityModel>
  23.     <service>
  24.       <securityTokenHandlers>
  25.         <add type="Microsoft.IdentityModel.OAuth.SWTSecurityTokenHandler, Microsoft.IdentityModel.OAuth, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  26.       </securityTokenHandlers>
  27.       <issuerNameRegistry type="SampleService.MySimpleRegistry, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  28.       <claimsAuthorizationManager type="SampleService.MySimpleClaimsAuthorizationManager, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  29.       <audienceUris>
  30.         <add value="http://localhost/" />
  31.       </audienceUris>
  32.       <issuerTokenResolver type="SampleService.WrapIssuerTokenResolver, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  33.     </service>
  34.   </microsoft.identityModel>
  35.   <startup>
  36.     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
  37.   </startup>
  38. </configuration>

 

In summary, these extensions implement OAuth WRAP protocol head for Windows Identity Foundation and re-uses all the neat WIF APIs for deriving the service behaviour. In the next post, I’ll discuss how to create a local OAuth WRAP issuer using the SecurityTokenService WIF API.

Feel free to download the source and experiment.

About these ads

6 Responses to “Using WIF for securing REST Service”

  1. velvel said

    Hi,

    Thanks for your blog post.
    I am trying to run the sample code and running into an issue.

    Question #1

    I am using your MyCustomIssuer as the OAuth issuer (as opposed to ACS)- so the only entry in WrapIssuerTokenResolver is for MyCustomIssuer

    Now I run the both MyCustomIssuer and SampleRestService host. I get a ready message on both in the console window.

    But when I call the Hello method via WebGet I get an exception

    Can you provide an example of what the syntax for OAuth token should look like

    Authorization: wrap access_token=XXXXXXXXXXXXXXX

  2. zamd said

    Hi there,

    Download & try this token requestor sample. It’s a Silverlight application which acquires tokens from ACS or a local issuer and can call a service using this token.

    Hope that helps

  3. velvel said

    Thanks.

    I could get it to work with the custom issuer.

    But cannot get it work with ACS ( sorry to continue to bother you). I use ACM.exe to generate an ACS Issuer, Policy, Scope and a Rule.

    Then I plugged it into the token requestor sample…..but I get an invalid token exception.

    A couple of things I tried:

    1) BTW, your code has the ACS NS hardcoded ( I don’t think is making a difference though)
    this.trustedTokenIssuer = string.Format(“https://zamd0192.accesscontrol.windows.net/”);

    2) IsHMACValid function assumes that swtWithSignature can be split into two parts. The token I am getting from ACS includes an expiration policy part. See below

    “OPRPRPRPRPRj61uH7ckQv6yCvasy0o%2fXUtfPHqC3r%2bpuktjE%3d&wrap_access_token_expires_in=3600″

    Should the &wrap_access_token_expires_in=3600 be treated as part of hash.

    3) Ultimately the locallyGeneratedSignature and swtWithSignature[1] don’t match, causing an exception

    4) I tried it both ways, treating &wrap_access_token_expires_in=3600 as part of the hash and not. In both cases the locally generated sig and hash don’t match.

    Any help will be greatly appreciated.

  4. velvel said

    I got it to work. A couple of steps for anyone who is trying this code out:

    1)Strip out &wrap_access_token_expires_in=3600 from the token

    2) Add an appropriate entry (AppliesTo) into the audience Uris section of the config.

  5. Aron David said

    Hi,
    I am trying to implement Outh or OAuth(2.0) inside a WCF Rest service. I haven’t used Rest Starter kit to write my WCF. Downloaded your code and going through that.
    Since a newbie could you please add a comment where to start and what are the secuirty stuff that I am supposed to pass along with the Http Header etc.
    Thaks for your effort.!
    Aron

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.

%d bloggers like this: