Poor Man’s Delegation: Web API Version 2, CORS and System.IdentityModel.Tokens.Jwt Part 2   2 comments

In Part 1 of this post I reviewed the goals of the project and how to create a simple JWT object.  In today’s post I will cover first, how to decode (validate) a JWT object and assign the Claims Principle created during that process to a thread on a running Windows applications.  Secondly I will cover the steps for using Web API to consume the JWT object and use its claims.  I will also review the new attribute based CORS filter (thanks again Brock Allen ).

Creating a Claims Principle from a JWT Object

Recall from Part 1 that we created a JWT object using an System.IdentityModel.Tokens.SecurityTokenDescriptor which we created specifically for our application.  Having received a JWT object the JWT is validated by creating a System.IdentityModel.Tokens.TokenValidationParameters object and then applying these parameters to the JWT object we wish to decode.  Note that the TokenValidationParameters mirror the values we supplied to the System.IdentityModel.Tokens.SecurityTokenDescriptor object to create the JWT.

var validationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
{
AllowedAudience = Constants.AllowedAudience,
SigningToken = Constatns.BinarySecretSecurityToken,
ValidIssuer = Constants.ValidIssuer
};

Given a JWT object called JWT we validate as:

var tokenHandler = new System.IdentityModel.Tokens.JwtSecurityTokenHandler();
tokenHandler.RequireExpirationTime = true;

var   principal = tokenHandler.ValidateToken(jwt, validationParameters);

The call to ValidateToken will fail with an exception if the TokenValidationParameters values do not match those used to create the object.  Further if the system time of the decoding system is outside of the Lifetime parameter of the JWT an exception will be thrown.  If all goes well the output of the call to ValidateToken is a ClaimsPrincipal object.  The ClaimsPrincipal object is a Framework 4.5 object which is the basis of the new look to Windows Framework security.  So far so good but at this point you are NOT delegating to the new Claims principle to do that you MUST assign the ClaimsPrincipal object to your thread and the HttpContext.Current.user

Thread.CurrentPrincipal = principal;
System.Web.HttpContext.Current.User = Thread.CurrentPrincipal ;

At this point the magic has happened, your thread is now running as a delegate of the JWT object.  There are limits (for your benefit) the user is marked as Authenticated and the Authentication Type is marked as Federated.  As a Federated user there are limits to your power.  You can not act as Local System in this delegated identity.  Ok that was easy.  Now lets turn to a slightly more difficult problem.

Web API and Authorization Delegating Handlers

In our simple design the user sends the JWT object as an argument to a standard HTTP Authorization Header  as a Bearer token.  Other methods (cookies, query parameters, form-encoded) are possible but the header method is a clean and very common.  Lets look now how Web API can process this header using a Authorization Filter.  The basic idea is

Derive a class from the Web API class DelegatingHandler, and

Override the SendAsync Method.

The model over ride looks like this  looks like this:

public class myJWTHandler : DelegatingHandler
{

      protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken )
{

            var auth=request.Headers.Authorization;

           if ( auth==null || auth.Scheme != “Bearer” )
{
var response=request.CreateResponse( HttpStatusCode.Unauthorized, string.Empty );
var tsc = new TaskCompletionSource<HttpResponseMessage>( );
tsc.SetResult( response );
return tsc.Task;
}
HttpStatusCode statusCode=HttpStatusCode.OK;

           //request.Headers.Authorization.Parameter is the JWT string

           //in this example

           //  _ValidateJWT assigns the claims principle to

           //  Thread.CurrentPrincipal and  System.Web.HttpContext.Current.User

           // on SUCCESS
if ( !_ValidateJWT( request, request.Headers.Authorization.Parameter, out statusCode ) )
{
var response=request.CreateResponse( statusCode, string.Empty );
var tsc = new TaskCompletionSource<HttpResponseMessage>( );
tsc.SetResult( response );
return tsc.Task;
}
return base.SendAsync( request, cancellationToken );
}

}

Now we need to assign our Handler to a URL route.  We do this in standard file WebApiConfig.cs following this simple pattern within the Register Method therein:

           System.Net.Http.DelegatingHandler[] myRouteDelegates=new System.Net.Http.DelegatingHandler[]{
new myJWTHandler()
};
var myRouteHandlers=System.Net.Http.HttpClientFactory.CreatePipeline(
new System.Web.Http.Dispatcher.HttpControllerDispatcher( config ), myRouteDelegates
);
config.Routes.MapHttpRoute(
name: “myRoute”,
routeTemplate: “myApplication//{accountNumber}”,//your route goes here
defaults: new
{
controller = “myController”,
action = “Get”
},
constraints: null,
handler: myRouteHandlers
);

Ok we are Hooked! Any call to “myRoute” will pass FIRST through the delegate Hander, which in turn enforces that a valid JWT object appears in the Authorization Header and will assign (delegate) the thread for the call to the Federated user specified within the JWT.

The  Route Controller and Actions

Now we want to add the following functionality:

  • Allow only authorized users in certain Roles to access the route controller (a Role is a claim), and
  • Use additional claims associated information with the federated user on our controller’s method thread.
  • Enable CORS Support.

The first two of these are pretty straight forward,  but CORS support with authorized users requires some additional design and programming.  CORS support is however required with the design we are playing out here.  More on this bellow.

Our basic controller looks something like this:

public class myBookGroup1Controller : ApiController

    {

        [HttpGet]

        [Authorize(Roles = "Insured")]

        [WebAPI.Handler.Enable_AIC_CORS()]  //CORS support derived from Wep API standard CORS Attribute

               public HttpResponseMessage Get( string prameter {}}

}

The attribute [HttpGet] filters requests and allows HTTPGet requests to call this action. The Authroize attribute leverages the claims Federated user.  In this case  [Authorize(Roles = "Insured")] we are asking for Authenticated Users who have a Roles claim whose value is “Customer”;  In order for this to work correctly we use the registered Microsoft Namespace: use “http://schemas.microsoft.com/ws/2008/06/identity/claims/role” as the key for “roles” when we created the JWT initially (way back in Part I).

Once we have entered an Action Method we can access the Federated Users Claims as:

  public static IEnumerable<string> GetClaims(System.Security.Principal.IPrincipal iPrince, string uni)

        {

            try

            {

                return from c in ((ClaimsPrincipal)iPrince).Claims where c.Type == uni select c.Value;

            }

            catch (Exception x)

            {

                throw new ApplicationException(“LINQ access Errors Key ” + uni,x);

            }

        }

The body of the Get method here could look like:

public HttpResponseMessage Get( string prameter) {}{

        var accountNumber = GetClaims(System.Web.HttpContext.Current.User, Constants.JWT);

//do something the “accountNumber”

         List<string> data=new List<string> data();

bool results=DoWork(prameter, out List<string> data);

if (results){

// good

                      return controller.Request.CreateResponse( System.Net.HttpStatusCode.OK, listTable );

}else{

//bad news

return controller.Request.CreateResponse( HttpStatusCode.BadRequest, “badness messages);

}

CORS Made Simple From Preflight Checklist to Take Off

The General Idea:  Cross Origin Resource Sharing is defined by the following scenario. A device connects to a web site subsequent AJAX calls from the device running “as” that  web application to a different web application must preform an additional handshake prior to authorizing the request.  The CORS specification requires additional handlers to be written on the server and the server must specify what the policy requirements imposed on the AJAX call. The user agent (the “browser” handles the device side of the handshake (this phase is called, for obscure reasons “Preflight”)  Brock Allen has done the heavy lifting for us and Web API 2 contains Attribute CORS support based on his design and code.  The policy requirements consist:

  • Allowed Origins:  What domains may make the call. Can be “*” for any if SupportsCredentials is false.
  • Allowed Methods:  “*” for all
  • AllowAnyHeader:    True/False. Incoming headers are not limited to the “standard” headers
  • SupportsCredentials:  true / false.  Supports equals Requires Authorization
  • Exposed Headers:  approved, non-standard headers which may be sent from the Server to the caller.

Wow.  There it is the good and the bad.  For an anonymous access action methods which can be accessed from ANY server, can be defined for CORS within Web API 2 with the attribute:

[EnableCORS(“*”,”*”,”*”)]

public HttpResponseMessage Get( string prameter) {}{

Things get form complex for authorization required sites. In this scenario:

Allowed Origins requires a list of allowed ULRs in proper form:  http:\\{mydomain.com}.  This can be a list of URLS.

If we want to expose a custom (non-standard) HTTP header from the server to the client we must list each header name here.

While this could be written out with constants, having this type of system parameter embedded in an attribute just seems wrong!  There is a way.

The Web API allows us to extend the EnableCORS attribute to allow us to read the list of actual values from …. somewhere (config file or database or whatever.

The basic idea is:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]

    public class Enable_AIC_CORSAttribute : Attribute, ICorsPolicyProvider

    {

        private CorsPolicy _Policy;

        private Dictionary<string, string> _AllowedOrigns()

       {

                      //get the proper list from somewhere

             return object;

       }

        private Dictionary<string, string> _ExposedHeaders()

{

                      //get the proper list from somewhere and format as a string

                   return Dictionary<string, string> obect;

};

private _FormatForCORS(){

    //work

return string object;

}

  public Enable_AIC_CORSAttribute()

        {

            _Policy = new CorsPolicy

            {

                AllowAnyHeader = true,

                SupportsCredentials = true,

            };

   _Policy.Methods.Add(“GET”);

           _Policy.Origins.Add(_FormatForCORS_AllowedOrigns())))

            _Policy.ExposedHeaders.Add(_FormatForCORS_ExposedHeaders()))

        }

  public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, System.Threading.CancellationToken cancel)

        {

            return Task.FromResult(_Policy);

        }

}

OK.  I think that’s it for now.  Lift Off.  Good Hunting.

2 responses to “Poor Man’s Delegation: Web API Version 2, CORS and System.IdentityModel.Tokens.Jwt Part 2

Subscribe to comments with RSS.

  1. Pingback: ASP.Net Web API: Cross-Domain AJAX and Server Techniques: JSONP and CORS | Cloud2013 Or Bust

  2. Pingback: REST, WEB API And CORS | Cloud2013 Or Bust

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.

Join 115 other followers

%d bloggers like this: