Basic Auth with Sitecore

A custom attribute can be created in order to support Basic Auth with a custom API. The end goal is to be able to use a new AuthorizeAccess attribute like this:

 namespace xxx.xxx.xxx  
 {  
   [AuthorizeAccess(Role = @"ROLENAME")]  
   public class TestController : ServicesApiController  
   {  
     [HttpGet]  
     public IHttpActionResult FetchItem(string identifier)  
     {  
       var contentItem = GET ITEM BASED ON THE IDENTIFIER;  
       if (contentItem != null)  
       {  
         return Ok(contentItem);  
       }  
       return Content(HttpStatusCode.NotFound, "Item not found");  
     }  
   }  
 }  

This new AuthorizeAccess attribute has a parameter called Role which accepts Sitecore roles and can be placed at the class or the action levels depending on the requirement. The goal is to return a 404 status code if the request comes with an authorization header (username:password base64 encoded) that does not belong to the specified role.

Let's get into the details of our new attribute, we need to create a class like this:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Net;  
 using System.Net.Http;  
 using System.Text;  
 using System.Web;  
 using System.Web.Mvc;  
 using ActionFilterAttribute = System.Web.Http.Filters.ActionFilterAttribute;  
 namespace xxx.xxx.xxx  
 {  
   [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]  
   public class AuthorizeAccessAttribute : ActionFilterAttribute  
   {  
     public string Role { get; set; }  
     public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext filterContext)  
     {  
       var authorizationHeader = HttpContext.Current.Request.Headers["Authorization"];  
       if (string.IsNullOrEmpty(authorizationHeader) || !IsUserInRole(authorizationHeader, Role))  
       {  
         filterContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);  
       }  
     }  
     private bool IsUserInRole(string authorizationHeader, string role)  
     {  
       if (string.IsNullOrEmpty(authorizationHeader))  
       {  
         throw new ArgumentNullException(nameof(authorizationHeader));  
       }  
       if (string.IsNullOrEmpty(role))  
       {  
         throw new ArgumentNullException(nameof(role));  
       }  
       string credentials = Encoding.UTF8.GetString(Convert.FromBase64String(authorizationHeader.Substring(BasicAuth.Length).Trim()));  
       var credentialsArray = credentials.Split(':');  
       string username = credentialsArray.First();  
       string password = credentialsArray.Last();  
       if (string.IsNullOrEmpty(username))  
       {  
         throw new ArgumentNullException(nameof(username));  
       }  
       if (string.IsNullOrEmpty(password))  
       {  
         throw new ArgumentNullException(nameof(password));  
       }  
       if (Sitecore.Security.Authentication.AuthenticationManager.Login(username, password))  
       {  
         var user = Sitecore.Security.Authentication.AuthenticationManager.GetActiveUser();  
         if (user != null && user.IsInRole(role))  
         {  
           return true;  
         }  
       }  
       return false;  
     }  
   }  
 }  

Now we only need to decorate our classes/actions and take advantage of Basic Auth.

Happy Sitecoring fellas!

Comments