Saturday, 15 September 2018

Intercept the HttpRequest for create a custom authentication using AuthenticationMiddleware Owin in WebApi


In this post we are going to see how to intercept HttpRequest for create a custom authentication using AuthenticationMiddleware owin in WebApi. For this we will take scenario like Pin based token authentication. For example users have to send the following header in each request for validate

Header Name: x-token-auth

This header must contain a value of pin token, that must be greater than 10000 for authorize, if it is less then we will state it as unauthorized.

Sample:
*********
x-token-auth: token|50000

In my previous post we did same kind of authentication using OwinMiddleware, Now we are going to do that using AuthenticationMiddleware Link for the previous post Create custom authentication using Owin Middleware


Steps to follow:
****************

  1. Create a class PinBasedAuthenticationOptions derive from AuthenticationOptions
  2. Create a middleware derive from AuthenticationMiddleware<PinBasedAuthenticationOptions>
  3. Create a Handler derive from AuthenticationHandler<PinBasedAuthenticationOptions>
  4. Create a another middleware derive from OwinMiddleware.
  5. Create a extension method which is used to map the middleware in the HttpRequest.
  6. Call the extension method in the startup.cs

Step 1:
********
Create a class PinBasedAuthenticationOptions derive from AuthenticationOptions and set the authentication type as PinBased_Token

public class PinBasedAuthenticationOptions : AuthenticationOptions
{
  internal const string Authentication_Type = "PinBased_Token";       

  public PinBasedAuthenticationOptions() : base(Authentication_Type)
  {
  }
}



Step 2:
********
Create a middleware derive from AuthenticationMiddleware<PinBasedAuthenticationOptions> we have to create a second parameter in the constructor which takes input param as PinBasedAuthenticationOptions and that constructor should be public.


    public class PinBasedMiddleware :                 
             AuthenticationMiddleware<PinBasedAuthenticationOptions>
    {
       public PinBasedMiddleware(OwinMiddleware next, PinBasedAuthenticationOptions options)           : base(next, options)
        {
        }

        protected override AuthenticationHandler<PinBasedAuthenticationOptions>                      CreateHandler()
        {
            return new PinAuthenticationHandler();
        }
    }



Step 3:
********
Create a Handler derive from AuthenticationHandler<PinBasedAuthenticationOptions>, Here in this handler we are checking the Request headers for the PinBased token if it is authorized then populate the ClaimsIdentity in the AuthenticationTicket, This will internally populate the user object in the Request.


public class PinAuthenticationHandler : AuthenticationHandler<PinBasedAuthenticationOptions>
    {
        public PinAuthenticationHandler()
        {
        }

        protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
        {           
            AuthenticationProperties properties = new AuthenticationProperties();
            var authenticationResult = new AuthenticationTicket(null, properties);
            bool authorised =  IsAuthorised(Request.Headers);
            if(authorised)
            {
                IEnumerable<Claim> claimCollection = new List<Claim>
                {
                    new Claim(ClaimTypes.NameIdentifier,"123456"),
                    new Claim(ClaimTypes.Country, "India"),
                    new Claim(ClaimTypes.Gender,"Male"),
                    new Claim(ClaimTypes.Email,"test@gmail.com"),
                    new Claim(ClaimTypes.Role, "SA"),
                    new Claim(ClaimTypes.Sid,Guid.NewGuid().ToString())
                };
      ClaimsIdentity claimsIdentity = new ClaimsIdentity(claimCollection,"Pin_Based");
      authenticationResult = new AuthenticationTicket(claimsIdentity, properties);                
            }
            return await Task.Run(() => authenticationResult);           
        }


        private bool IsAuthorised(IHeaderDictionary requestHeaders)
        {
          string []pinValues;
          bool pinHeaderPresent = requestHeaders.TryGetValue("x-token-auth", out pinValues);
            if (pinHeaderPresent)
            {
                string[] valuesInHeader = pinValues.ToList()[0].Split(new char[] { '|' }, 
                                              StringSplitOptions.RemoveEmptyEntries);
                if (valuesInHeader.Length == 2)
                {
                    int pin;
                    if (int.TryParse(valuesInHeader[1], out pin))
                    {
                        if (pin >= 10000)
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        }

    }




Step 4:
********
Create a another middleware derive from OwinMiddleware.In this middleware we are checking whether user object in the request is populated or not, if it is not populated then we are setting the StatusCode for response as UnAuthorized.

    public class PinBasedPostAuthenticationMiddleware : OwinMiddleware
    {
        public PinBasedPostAuthenticationMiddleware(OwinMiddleware next) : base(next)
        {
        }

        public override async Task Invoke(IOwinContext context)
        {
            if (context.Request.User == null)
            {
                context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            }
            else
            {
                await Next.Invoke(context);
            }
        }
    }


Step 5:
********
Create a extension method which is used to map the middleware in the HttpRequest. Here in this extension method we are using the middleware based on the pipeline stage, so middleware will run stage by stage , one by one.


    public static class PinAuthenticationExtension
    {
        public static void UsePinBasedAuthentication(this IAppBuilder builder)
        {
            builder.MapWhen((context) => true, (app) =>
               {
                   app.Use<PinBasedMiddleware>(new PinBasedAuthenticationOptions());
                   app.UseStageMarker(PipelineStage.Authenticate);

                   app.Use<PinBasedPostAuthenticationMiddleware>();
                   app.UseStageMarker(PipelineStage.PostAuthenticate);
               });            
        }
         }


Step 6:
********
Call the extension method in the startup.cs

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UsePinBasedAuthentication();
        }       
    }



Controller:
***********
public class ValuesController : ApiController
    {
        // GET api/values
        public IHttpActionResult Get()
        {           
            var data = new string[] { "value1""value2" };
            return Ok(data);
        }

        // GET api/values/5
        public string Get(int id)
        {
            var data = "Rajesh";
            return data;
        }

        // POST api/values
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }
       
    }


Output:
**********

Make a call to the endpoint with pin value less than 10000 using postman will result in UnAuthorized






Make a call to the endpoint with pin value greater than 10000 using postman will result in success authentication




From this post you can learn how to intercept the HttpRequest for create a custom authentication using AuthenticationMiddleware Owin in WebApi

















No comments:

Post a Comment