The Freak Parade

Strange noises from the mind of Nathan Stults…
  • rss
  • Home
  • About The Freak Parade

Flowing Identity from a Client to a Service when using RESTful WCF Part 2 - A Solution

September 1, 2008

This post will describe a technique to transparently insert a custom HTTP header into all requests generated by a WCF REST proxy, as well as a technique to extract that HTTP header from the request at the service for the purpose of flowing the digital identity of an authenticated user from a REST client to a REST service. In this case, digital identity is represented by an authorization token, which is just a string. You can read a detailed description of the problem in Part 1 of this post. A complete sample project containing the full source code of the solution is on CodePlex.

The basic idea is to insert a custom action into the WCF message pipeline that will extract a security token representing the identity of the currently logged in user and add the value of that token (just a string) to the outgoing API call (an HTTP request) by way of a custom HTTP header. Once the request is received by the service, a custom action inserted into the receive pipeline checks for the custom header and, upon finding it, de-serializes the identity token and uses the claims contained within it to set an appropriate security context (in this case by setting Thread.CurrentPrincipal).

Setting a Custom HTTP Header - The Easy Way

On the client side, I am making the assumption that a user has been authenticated somehow, is associated with a set of claims, and that a representation of the user along with her claims can be found at Thread.CurrentPrincipal. In anticipation of using Microsoft’s new Zermatt Identity framework, which introduces IClaimsPrincipal and IClaimsIdentity, we implemented our own versions of these interfaces. They will eventually be replaced by the Zermatt types once we start integrating Zermatt into our application. IClaimsPrincipal maintains a reference to IClaimsIdentity, which has a property of type IList<IClaim> that represents all the authorization relevant attributes of a user. Please see this post for a discussion of claims based identity management. The interface IClaim is pretty much just a name value pair.

Adding a custom header to a request is trivial if you add the header in the same scope as the service call made on the proxy. You can just wrap the entire call in an OperationContextScope using statement, and use the Headers property of WebOperationContext.Current:


using (var factory = new WebChannelFactory<imyservice>())
{
  IMyService proxy = factory.CreateChannel();
  using (new OperationContextScope((IClientChannel) proxy))
  {
    WebOperationContext.Current.OutgoingRequest.Headers.Add('x-mycompany-auth',
                                                            'tokenString');
    proxy.DoItToIt();
  }
}

That technique works, and would probably be just fine if you only needed to add the authorization token to a few select calls. However, in our scenario, we want to add the token to *every* call, so wrapping each API call with all that scoping garbage isn’t going to cut it. It’s ugly and about as un-DRY as it gets.

Extending WCF - The Transparent Way

The solution, of course, is to take advantage of the WCF extensibility points available to both the client and the server. We want to choose spots in the messaging pipelines as close to the actual delivery/receipt of the message as possible.That would be the the Message Inspection phase on the client and the Operation Context Initialization phase on the server.

WCF can be made to jump through our hoops by following these steps:

On the client side we need to

1. Define the MessageInspector

2. Create a behavior to register the MessageInspector

3. Install the behavior on the channel factory.

On the service side we need to

4. Define a OperationContextInitializer

5. Create a behavior to register the extension

6. Apply the behavior to the service.

The end result is that Thread.CurrentPrincipal on the service side will always reference an IClaimsPrincipal with the same claims associated with the Thread.CurrentPrincipal on the service consumer, and we can test those claims to authorize access, as demonstrated in

7. Use.

1. The MessageInspector


 public class ClientAuthMessageInspector : IClientMessageInspector
 {
        #region IClientMessageInspector Members

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            //Get the HttpRequestMessage property from the Message
            var httpRequest =
                request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;

            //Make sure we have a valid property, or create one
            if (httpRequest == null)
            {
                httpRequest = new HttpRequestMessageProperty();
                request.Properties.Add(HttpRequestMessageProperty.Name, httpRequest);
            }

            //Add your token to the header. Simple as that.
            //In real life, we injected an ITokenProvider using an IoC,
            //instead of using static methods directly, but that was
            //overkill for a sample.
            httpRequest.Headers.Add(AuthenticationHelper.AUTH_TOKEN_HEADER_NAME,
                                    AuthenticationHelper.GetAuthTokenForCurrentUser());

            return null;
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            //nop
        }

        #endregion
 }

2. The Behavior


public class ClientAuthBehavior : IEndpointBehavior
{
        private readonly ClientAuthMessageInspector _messageInspector;

        public ClientAuthBehavior(ClientAuthMessageInspector messageInspector)
        {
            _messageInspector = messageInspector;
        }

        #region IEndpointBehavior Members

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            //Install the message inspector
            clientRuntime.MessageInspectors.Add(_messageInspector);
        }

        //no-op method implementations elided for clarity.
	//See the sample project for the complete
	//code listing.

        #endregion
}

3. Apply


 private void InitializeChannelFactory()
 {
    _channelFactory = new WebChannelFactory<imonkeyshavingservice>("shavingService");
    _channelFactory.Endpoint.Behaviors.Add(new ClientAuthBehavior());
 }

4. On the Service Side…OperationContextInitializer


 public class ClaimsAuthContextInitializer : ICallContextInitializer
 {
     #region ICallContextInitializer Members
      public Object BeforeInvoke(InstanceContext instanceContext,
                                IClientChannel channel,
                                Message message)
     {
         DetectCurrentUser();
         return null;
     }

     public void AfterInvoke(Object correlationState)
     {
     }
     #endregion

     private static void DetectCurrentUser()
     {
         if (WebOperationContext.Current == null)
             throw new InvalidOperationException("Only HTTP web requests are supported for this version of the API");

          string authToken = WebOperationContext.Current
             .IncomingRequest
             .Headers[AuthenticationHelper.AUTH_TOKEN_HEADER_NAME];

         if (AuthenticationHelper.SetCurrentUserFromAuthToken(authToken) == false)
         {
             WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
                throw new UnauthorizedAccessException(
                 "No authentication token was found in the headers of the current request.");
         }
    }
 }

5. The Behavior


[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class ClaimsAuthServiceBehavior : Attribute, IServiceBehavior
    {
        #region IServiceBehavior Members

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
                                         Collection<serviceendpoint> endpoints,
                                         BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
            {
                var cd = cdb as ChannelDispatcher;

                if (cd != null)
                {
                    foreach (EndpointDispatcher ed in cd.Endpoints)
                    {

                        foreach (var dispatchOperation in
                            ed.DispatchRuntime.Operations)
                        {
                            dispatchOperation.CallContextInitializers
                                .Add(new ClaimsAuthContextInitializer());
                        }

                    }
                }
            }
        }

        #endregion

6. Apply


 static void Main(string[] args)
 {
      _host = new WebServiceHost(typeof(MonkeyShavingService),
                                 new Uri("http://localhost:8000"));

      _host.Description.Behaviors.Add(new ClaimsAuthServiceBehavior());

       var binding = new WebHttpBinding();
       _host.AddServiceEndpoint(typeof(IMonkeyShavingService), binding, "");

       _host.Open();

       Console.WriteLine("Press any key to exit.");
       Console.ReadKey();
 }

7. Last but not least, Use (this is a sample service method that restricts access to certain users)


 public Monkey PutMonkeyInShaver(Monkey monkey)
 {
      //Only authenticated users can add monkeys to the shaver
      if (CurrentUser == null)
      {
       SetStatusCode(HttpStatusCode.Forbidden,
                     "Only authenticated users can put monkeys in the shaver.");
       return null;
      }

      _monkeys.Add(monkey);
      ShaveMonkey(monkey);
      return monkey;
 }

 private IClaimsPrincipal CurrentUser
 {
     get { return Thread.CurrentPrincipal as IClaimsPrincipal; }
 }

It works, but…

Our ultimate solution does not extend or take advantage of any of the claims based security features built into WCF. While it may be possible to do so, it wasn’t immediately obvious to us how to go about it, so the solution presented here handles authorization out of band from the built in WCF authorization mechanisms.

As you may have guessed, I am NOT a WCF expert. That means that the approach outlined here could very well be a cheap hack for a problem solvable in a much more elegant way. If by some chance you happen across this post and know that to be the case, I’d love to hear your thoughts on the subject :) I wasn’t able to find any guidance during my own research that hinted at a more appropriate approach to solving this problem, but that certainly doesn’t mean one doesn’t exist.

About the Sample Application

The sample application can be downloaded here and includes a complete, end to end REST API implemented in WCF. It includes separate DLL’s to represent the Service, the Contracts, the Client, a Service Host and a Utility DLL that contains shared authentication and authorization code. To get the most from the sample you should run the Service Consumer project, a Windows Forms application that allows you to invoke various operations of the API while impersonating users with various roles. In addition to demonstrating a possible approach to flowing a claims-based security token through a REST API, the sample demonstrates a fully functional, RESTful WCF service, which may be useful to you in its own right.

Here is a screen shot of the sample Windows Forms service client:

What’s Next

In the future I will be enhancing the sample to demonstrate our approach to defining authorization policies that operate against a set of claims using our Simple Expression Evaluator project, currently on CodePlex. This technique will show how a simple but powerful and flexible claims-aware rules engine can easily be constructed using any expression evaluator and a set of claims.

Comments
Comments
Categories
Identity, REST
Comments rss Comments rss
Trackback Trackback

Flowing Identity from a Client to a Service when using RESTful WCF Part 1 - The Problem

The digital representation (or identity) of users accessing connected applications will be increasingly modeled using the the concept of Claims. If you’re workingimage with SOAP based web services then the problem of how to implement claims based access control into your WCF services is is a fully solved problem. Whether or not you are using the new Zermatt framework or the claims based identity support in the System.IdentityModel namespace there exists plenty of guidance, available on the web and in books, to help you get everything wired together in a predetermined way. If you’re writing a REST API, however, things aren’t so simple.

SOAP vs REST in WCF - who cares? A service is a service, right?

All of the claims based security support in WCF relies on SOAP envelope headers to transmit a user’s claims from the service consumer to the service. This is to be expected, as several WS-* specs play an important role in WCF’s security support. As a result, if you are using a SOAPless WCF binding such as the RESTful WebHttpBinding, the best you can get for free is transport level security. That means you’re pretty much limited to transmitting authentication credentials, such as a username/password pair (via Http Basic Auth) , a Certificate, etc. If you have a security token containing claims you’d like to pass along, such as a SAML token, it isn’t immediately obvious how to flow that token from the service consumer to the service provider.

Hey, SOAP doesn’t have a patent on Envelopes!

In a RESTful API there is no “envelope” inherent in the message payload itself like there is with SOAP messages.  Indeed, when retrieving data from a RESTful service, there is no message payload at all. The entire scope of a GET request is communicated via the URL. Unlike SOAP, however, the transport protocol you will be using with REST is not a configurable, deploy-time variable. REST operates over HTTP by definition, and the HTTP protocol specifies its own message envelope that supports message headers. These are just the standard, everyday HTTP headers you already know and love. Therefore, we decided the best place for a security token to be stashed when working with RESTful WCF was in a custom HTTP header.

Where do you get a security token from in the first place?

Actually, I’m not going to go into how you go about authenticating a user and obtaining a claim-laden security token (usually a signed, encrypted SAML token). Zermatt should be able to help out with this (see this post for how), and there are also inexpensive .NET libraries you can buy that will abstract away the yucky cryptography/SAML aspects of creating and consuming a proper token. You can even leave these details until the Last Responsible Moment if you want, and, like we are doing, stub out the process of building or obtaining a proper interoperable token and temporarily substitute a simple plain text, character-delimited or XML serialized list of claims to getting everything working and tested and then plug in the gory details later in the process when you’ve selected a vendor/platform/framework as your Security Token Service (STS). For more info on building or buying an STS, see here and here.

The problem distilled

So that leaves us with only a single problem: how do we send a custom HTTP Header containing the logged in users security token with each service request without giving up the convenience of runtime-generated proxies via the WebHttpChannelFactory? Ok, there is another (small) part to the problem: how do we read this custom header on the service side of the wire early enough in the WCF lifecycle so we can unpack the embedded claims and make them available to the service implementation for making authorization decisions?

WCF Extensibility to the rescue!

The specifics of the solution, and code samples, will be presented in the next post.

Comments
Comments
Categories
Identity, REST
Comments rss Comments rss
Trackback Trackback

How the Grinch Stole REST

August 13, 2008

My interest in the REST approach to cross-process communication has been growing little by little over time like condensation on the back of my brain, almost without my noticing it. In the front of image my mind I have always focused my energies on learning SOAP web services and The WS-* Way. Whenever there was a REST vs SOAP debate I always came down on the side of SOAP, citing the usual examples: electronically discoverable contracts, automatic proxy generation, security, encryption, transactions, WS-*, blah blah blah. I think, though, that despite my tendency to feel like I was making an informed decision based on available evidence, in reality I was simply borrowing my opinion from my environment rather than applying the strengths and weaknesses of the two approaches to the actual messaging requirements of the systems I was building.

When you are young and first start having adult conversations, and such a conversation turns political, many people will argue on behalf of an ideology inherited from their parents or older peers. Most can even argue intelligently and coherently using borrowed rhetoric. Some people may never grow out of this tendency, but many others will begin to combine their first impressions with their own unfolding experience of the world and either gradually or all of the sudden realize they no longer believe what they thought they believed.

In any case, despite my conscious disregard for REST whenever I bothered to think critically about it, the sheer volume of media coverage about the subject worked its way into my curiosity. After all, REST API’s are everywhere. Even WCF now natively and comfortably supports building REST based messaging endpoints. Then the other day I read this article and realized that while I’m absolutely sure everything I’ve learned to believe about SOAP is entirely true, the requirements of the systems I work on very often don’t actually demand (or justify) most of the strengths of SOAP (or the Gordion’s Knot of complex WS-* standards).

imageThis realization didn’t suddenly swing my opinion to the REST side, the decision of which approach to use in any given situation will need to be made on a case by case basis, of course, but my toolbox grew three sizes that day. What surprised me about this experience is that I always felt I was weighing my options evenly and making technical decisions based on the parameters of the problem at hand, but in reality my mind was always already made up! There was never a real choice.

Maybe one of the more interesting kinds of professional growth is not just acquiring new technology skills, but also the shedding of these very subtle preconceptions that artificially limit your options.

Of course, not only are such unsubstantiated prejudices unavoidable but are also a complexity reducing necessity. If the entire gamut of available technology needed to be evaluated for every technical decision, you’d never make any progress on anything. Choices made by the subconscious, even when due to prejudice, keep the ball rolling.

There is no moral to any of this, though. I don’t think we have much control over the situation. Preconceived notions will continue grow and shed cyclically as long as we are alive, like a snakes many skins, and the conscious mind can do little more than take credit for the good decisions and apply shame for the not-so-good ones, but that’s how we roll, brotha.

Comments
Comments
Categories
General, REST
Comments rss Comments rss
Trackback Trackback

Rinsing the SOAP from WCF (or, RESTful WCF Hyperlink Acupuncture)

August 12, 2008

.NET 3.5 SP1 stealthily went RTM yesterday, as I’m sure none of you have noticed. It’s a big, Roly Poly bug of image a service pack, and it comes with some nice enhancements to the REST oriented features introduced to WCF in version 3.5. Also included in SP1 is a tangential enhancement to WCF that removes the requirement to decorate DataContracts with WCF attributes.

First, for those of you sexy Web 2.0 Jockeys who could design a textbook REST API with your eyes closed and a pint of Johnny Walker coursing through your veins, I’ve provided a list of resources specifically about implementing REST services using WCF. There are also a few RESTish ASP.NET MVC links sprinkled in the mix, to add a little bit of flava.

Then, for REST neophytes such as myself, there are some resources to help you get your mind around the REST style itself, independent of WCF, which I highly recommend taking the time to do. Just as the use of SOAP Web Services does not magically transform your stinking rats nest of ad hoc, RPC style web services into a Service Oriented Architecture, simple use of XML or JSON over HTTP does not mean you are applying the REST architectural style. Not to imply that a stinking rats nest is bad, or that POX/JSON over HTTP is bad, it just isn’t necessarily RESTful.

None of the links presented here have much interest in the REST vs SOAP debate. There are trillions upon trillions of terabytes of available blather on REST vs SOAP and SOAP vs REST and Soapy REST vs Resting SOAP. If you want help deciding between the two, ask that scary looking guy in the corner there and he’ll show you to the REST vs SOAP room. Um, I would change out of the chaps first. Much better. (I will post one link though, to a podcast by Udi Dahan on the subject, because it is a pretty balanced discussion  and because it is sitting open in my browser and won’t cause me to do any extra typing. Fine, I lied, I’ll also link to an Information Week article about Web Oriented Architecture (WOA) and SOA that piqued my interest in the subject in the first place).

And now buckle up kids, here we go…

RESTful WCF

Zen of the Web Programming Model (Part 1) : Brain.Save()
Kirk Allen Evans’s Blog : Creating RESTful Services Using WCF
Kirk Allen Evans’s Blog : Creating a REST Twitter Client With WCF
More on RESTful Service with WCF and POX/POCO - Johan Danforth’s Blog

Ajax & RESTful WCF

Calling Web Services via AJAX - Part 1
Calling Web Services via AJAX - Part 2
jQuery AJAX calls to a WCF REST Service - Rick Strahl’s Web Log
WCF REST Configuration for ASP.NET AJAX and plain REST Services - Rick Strahl’s Web Log
CoDe Magazine - Article: REST-Based Ajax Services with WCF in .NET 3.5
Return JSON from a RESTful service

Speciality Topics

Dan Rigsby » REST Services and Metadata Endpoints in WCF
WCF, WebHttp Binding, and Authentication

Screencasts

InfoQ: Rob Windsor on WCF with REST, JSON and RSS

Not everyone’s experience with the REST support in WCF 3.5 has been like sucking sugar water from a humming-bird feeder though:

Using WCF for REST, Part 1, Part2 and Part 3. Make sure you read all the comments though, several of the gripes brought up in these posts have been addressed with SP1.

UriTemplate, UriTemplateTable
A must read reference document on MSDN describing in gory details how the UriTemplate works.

RESTful ASP.NET MVC

ASP.NET MVC: Using RESTful Architecture : Rob Conery
MS MVC: Simply Restful Routing | Adam Tybor’s Blog
Creating a RESTful POX Service using the ASP.NET MVC Framework [The .NET Addict's Blog]
Unifying Web "Sites" and Web Services with the ASP.NET MVC Framework | Aaron Lerch
ASP.NET MVC Tip #5 - Submitting an AJAX Form with jQuery - Mike Bosch’s Blog on .NET

This next one isn’t really about REST, but if you’re going to be creating a non-public REST API, you’re going to want to be using SSL as REST, not being a standard like SOAP, doesn’t have cool built-in encryption magic.

Steve Sanderson’s blog » Blog Archive » Adding HTTPS/SSL support to ASP.NET MVC routing

RESTful REST

RESTful Web Services | O’Reilly Media
This is a book by Sam Ruby and Leonard Richardson and is cited by just about every blogger that even has the word REST pop up their comments. And it was reviewed here. I have a copy on order, so I can’t tell you first hand how great it is, but I have read its praises many times today, so I am betting it is a very good place to start. As a bonus, the examples are mostly in Ruby - which I am ashamed to admin I’ve never actually learned to read, but maybe this is a perfect opportunity.

General RESTness
REST for the Rest of Us
REST for the Weary
Plain Old Stan: Understanding REST - a disgrace of Wikipedia definition

RESTful Services
RESTful Service - Ajax Patterns
Building Web Services the REST Way

RESTful API Design
Dustin R. Callaway - Design the REST API
Two Cardinal Sins of REST API Design: Lessons… from the NewsGator REST API
XML.com: How to Create a REST Protocol
Tarlog on Java: How to use SAML with REST Web Services

Comments
Comments
Categories
AJAX, ASP.NET MVC, MVC, REST, SOA, WCF, WOA, Web Development
Comments rss Comments rss
Trackback Trackback

Subscribe

Calendar

January 2009
M T W T F S S
« Nov    
 1234
567891011
12131415161718
19202122232425
262728293031  

Recent Posts

  • You Can’t Fill an Imaginary Hole
  • I don’t know but I’ve been told, ETL is gettin’ mighty old. BAM! BAM! EDA! I want my data right away!
  • Be Prepared To Be Surprised
  • Google Chrome, I could kiss you! (Or, multi-process browsers are a really good idea)
  • New Open Source .NET CMS/EPS Platform Released Today: Sense/Net 6.0 Beta 1

Recent Comments

  • Ashwani on Rule Based Access Control using an Expression Evaluator
  • Richers Blog on Identity’s new Identity - Part 3, The Technology
  • sandra on ESB’s for the Microsoft (.NET) Platform
  • nstults on Content Management Systems (CMS) for the .NET Platform
  • Adz on Content Management Systems (CMS) for the .NET Platform

Tags

TDD Testing

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox