Please enable Javascript to correctly display the contents on Dot Net Tricks!

Securing ASP.NET Web API using basic Authentication

 Print 
  Author : Shailendra Chauhan
Posted On : 22 Mar 2014
Total Views : 106,907   
Updated On : 26 Sep 2016
 

In previous article, I have explained Custom Authentication and Authorization in ASP.NET MVC. Now, I am going to show you how to implement basic HTTP authentication for your Web API by extending ASP.NET WEB API's AuthotrizeAttribute. Before implementing basic HTTP authentication, let's understand what is it?

Basic HTTP Authentication

In basic HTTP authentication the client passes their username and password in the HTTP request header. Typically, using this technique we encrypt user credentials string into base64 encoded string and decrypt this base64 encoded string into plain text. You can also use another encryption and decryption technique.

Custom Principal

Since WebAPI is build on the top of ASP.NET Framework, hence it can use ASP.NET Framework features like ASP.NET membership and provider. ASP.NET provides IPrincipal and IIdentity interfaces to represents the identity and role for a user. For ASP.NET Web API, you can also create a custom solution by evaluating the IPrincipal and IIdentity interfaces which are bound to the HttpContext as well as the current thread.

public class CustomPrincipal : IPrincipal
 {
 public IIdentity Identity { get; private set; }
 public bool IsInRole(string role)
 {
 if (roles.Any(r => role.Contains(r)))
 {
 return true;
 }
 else
 {
 return false;
 }
 }

 public CustomPrincipal(string Username)
 {
 this.Identity = new GenericIdentity(Username);
 }

 public int UserId { get; set; }
 public string FirstName { get; set; }
 public string LastName { get; set; }
 public string[] roles { get; set; }
 } 

Now you can put this CustomPrincipal objects into the thread’s currentPrinciple property and into the HttpContext’s User property to accomplish your custom authentication and authorization process.

Custom ASP.NET Web API Authorization Filter

Like ASP.NET MVC, Web API also provides Authorization filter to authorize a user. This filter can be applied to an action, a controller, or even globally. This filter is based on AuthorizeAttribute class exist in System.Web.Http namespace. You can customize this filter by overriding OnAuthorization() method as shown below:

//custom authorize filter attribute
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
 private const string BasicAuthResponseHeader = "WWW-Authenticate";
 private const string BasicAuthResponseHeaderValue = "Basic";
 readonly DataContext Context = new DataContext();

 public string UsersConfigKey { get; set; }
 public string RolesConfigKey { get; set; }

 protected CustomPrincipal CurrentUser
 {
 get { return Thread.CurrentPrincipal as CustomPrincipal; }
 set { Thread.CurrentPrincipal = value as CustomPrincipal; }
 }

 public override void OnAuthorization(HttpActionContext actionContext)
 {
 try
 {
 AuthenticationHeaderValue authValue = actionContext.Request.Headers.Authorization;

 if (authValue != null && !String.IsNullOrWhiteSpace(authValue.Parameter) && authValue.Scheme == BasicAuthResponseHeaderValue)
 {
 Credentials parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);

 if (parsedCredentials != null)
 {
 var user = Context.Users.Where(u => u.Username == parsedCredentials.Username && u.Password == parsedCredentials.Password).FirstOrDefault();
 if (user != null)
 {
 var roles = user.Roles.Select(m => m.RoleName).ToArray();
 var authorizedUsers = ConfigurationManager.AppSettings[UsersConfigKey];
 var authorizedRoles = ConfigurationManager.AppSettings[RolesConfigKey];

 Users = String.IsNullOrEmpty(Users) ? authorizedUsers : Users;
 Roles = String.IsNullOrEmpty(Roles) ? authorizedRoles : Roles;

 CurrentUser = new CustomPrincipal(parsedCredentials.Username, roles);

 if (!String.IsNullOrEmpty(Roles))
 {
 if (!CurrentUser.IsInRole(Roles))
 {
 actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
 actionContext.Response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
 return;
 }
 }

 if (!String.IsNullOrEmpty(Users))
 {
 if (!Users.Contains(CurrentUser.UserId.ToString()))
 {
 actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
 actionContext.Response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
 return;
 }
 }

 }
 }
 }
 }
 catch (Exception)
 {
 actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
 actionContext.Response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
 return;

 }
 }

 private Credentials ParseAuthorizationHeader(string authHeader)
 {
 string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(authHeader)).Split(new[] { ':' });

 if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[1]))
 return null;

 return new Credentials() { Username = credentials[0], Password = credentials[1], };
 }
}
//Client credential
public class Credentials
{
 public string Username { get; set; }
 public string Password { get; set; }
}

Applying CustomAuthorize attribute

To make secure your service, decorate your Web API controllers with CustomAuthorize attribute as defined above and specify the uses or roles to access specific service actions/methods. The below product service action Getproduct can be access only by Admin users.

public class ProductController : ApiController
{
 [CustomAuthorize(Roles="Admin")]
 public HttpResponseMessage Getproducts()
 {
 var products = new Product[]
 {
 new Product()
 {
 Id = 1,
 Name = "Soap",
 Price =25.12
 },
 new Product()
 {
 Id = 2,
 Name = "Shampoo",
 Price =25.12
 }
 };

 var response = Request.CreateResponse>(HttpStatusCode.OK, products);
 return response;
 }
}

Calling Web API and passing client credential from ASP.NET MVC

public class HomeController : Controller
{
 //
 // GET: /Home/
 public ActionResult Index()
 {
 string FullName = User.FirstName + " " + User.LastName; 
 
 HttpClient client = new HttpClient();
 
 string authInfo = "admin" + ":" + "123456";
 authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
 client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authInfo);

 client.BaseAddress = new Uri("http://localhost:63173/");

 HttpResponseMessage response = client.GetAsync("api/product/").Result;
 if (response.IsSuccessStatusCode)
 {
 // Parse the response body. Blocking!
 var data = response.Content.ReadAsAsync>().Result;
 return View();
 }
 return View();
 }
}
What do you think?

I hope you will enjoy the tips while implementing role-based or user-based security in your ASP.NET Web API. I would like to have feedback from my blog readers. Your valuable feedback, question, or comments about this article are always welcome.



Free Interview Books
 
COMMENTS
18 NOV
Angular with Firebase (Classroom)
04:00 PM-07:00 PM IST(+5:30)
18 NOV
Angular2+4 with Firebase (Online)
10:30 AM-12:30 PM IST(+5.30 GMT)
11 NOV
ASP.NET MVC (Online)
08:00 AM-10:00 AM IST / 09:30 PM To 11:30 PM(CST)
11 NOV
ASP.NET MVC (Classroom)
09:00 AM to 12:00 AM
7 NOV
Developing Microsoft Azure Solutions (Online)
07:00 AM-08:30 AM IST/ 8:30 Pm -10:00 PM CST
14 OCT
Angular2 and Angular4 (Online)
03:00 PM-05:00 PM IST (+5.30GMT)
12 OCT
ASP.NET Core (Online)
09:00 PM - 11:00 PM IST(+5:30 GMT)
10 OCT
Microsoft Azure Infrastructure Solutions (Online)
08:00 AM-09:30 AM IST / 09:30 PM -11:00 PM CST
LIKE US ON FACEBOOK
 
+