Skip to content

Mixing windows & forms authentication

I came across a situation today where I needed to mix two different authentication types on ASP.net MVC 4 application. The reason for this being that the client requirements, that although they use Active Directory they did not want to manage roles and responisbilities in an application through Active Directory. They still wanted the ability for administrators defined in an application to manage roles and access.

I experimented a little on how to achieve this, and the following is a solution I came up with.

I created an ASP.net MVC 4 application and enabled it with Windows Authentication. I then created a class within the application to inherit from the WindowsPrincipal.

 public class CustomPrincipal : WindowsPrincipal
    {
        public CustomPrincipal(WindowsIdentity identity)
            : base(identity)
        {
        }

        public IEnumerable Roles { get; set; }
    }

I also created a Principal Serializable model class, which we will use to serialise the data to JavaScript

 public class PrincipalSerializeModel
    {
        public IEnumerable Roles { get; set; }
    }

I created an interface for a basic security service  that will be used to get the role data from the database.

namespace Tab.Interface.Service
{
    public interface ISecurityService
    {
        IEnumerable GetRoles(string username);
    }
}

The concrete implementation of the class, is a really simple class that just gets some values from the database. I used the repository pattern for this.

 public class SecurityService : ISecurityService
    {
        private readonly IRoleRepository _roleRepository;
        public SecurityService(IRoleRepository roleRepository)
        {
            _roleRepository = roleRepository;
        }
        public IEnumerable GetRoles(string username)
        {
            var roles = _roleRepository.GetUserRoles(username);
            return roles.AsEnumerable();
        }
    }


We'll be using Unity as IOC container, so just some simple Set up ocde to set up our dependencies i.e. Security Service and Repositories, so we'll just wire up unity

public class UnityConfig
    {
        /// Registers the type mappings with the Unity container.
        ///The unity container to configure.
        /// 
        ///     There is no need to register concrete types such as controllers or API controllers (unless you want to
        ///     change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.
        /// 
        public static void RegisterTypes(IUnityContainer container)
        {
            container.RegisterTypes(
                AllClasses.FromLoadedAssemblies().Where(
                    t => t.Namespace.StartsWith("Tab")),
                WithMappings.FromMatchingInterface,
                WithName.Default,
                WithLifetime.ContainerControlled);
        }

        #region Unity Container

        private static readonly Lazy container = new Lazy(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        /// 
        ///     Gets the configured Unity container.
        /// 
        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }

        #endregion
    }

In the Global asax I implemented the code within the WindowsAuthentication_OnAutenticate method

	 protected void WindowsAuthentication_OnAuthenticate(object sender, WindowsAuthenticationEventArgs e)
        {
            if (e.Identity != null && e.Identity.IsAuthenticated)
            {
                var cookieName = string.Concat(e.Identity.Name, CookieExt);
                if (HttpContext.Current.Request.Cookies[cookieName] == null)
                {
                    string encTicket;
					
                    var securityService = DependencyResolver.Current.GetService(); //Call to IOC container to get service
                    var roles = securityService.GetRoles(e.Identity.Name);
                    var serializeModel = new PrincipalSerializeModel
                    {
                        Roles = roles.AsEnumerable()
                    };
                    var serializer = new JavaScriptSerializer();
                    var userData = serializer.Serialize(serializeModel);
                    var autTicket = new FormsAuthenticationTicket(1, cookieName, DateTime.Now,
                        DateTime.Now.AddMinutes(2), false, userData);
                    encTicket = FormsAuthentication.Encrypt(autTicket);
                    var cookie = new HttpCookie(cookieName, encTicket) {HttpOnly = true};
                    HttpContext.Current.Response.Cookies.Add(cookie);
                }
            }
        }

I also implemented a Security Attribute

		 public class SecurityAuthorizeAttribute : AuthorizeAttribute
    {
        public string Role { get; set; }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var isAuthorized = base.AuthorizeCore(httpContext);
            if (!isAuthorized) return false;
            CustomPrincipal principal = null;


           
            var accessCookie = httpContext.Request.Cookies[httpContext.User.Identity.Name];
            if (accessCookie != null)
            {
                var authTicket = FormsAuthentication.Decrypt(accessCookie.Value);
                var serializer = new JavaScriptSerializer();
                if (authTicket != null)
                {
                    var serializeModel = serializer.Deserialize(authTicket.UserData);

                    principal = new TabPrincipal(WindowsIdentity.GetCurrent())
                    {
                        Roles = serializeModel.Roles
                    };
                }
                HttpContext.Current.User = principal;
            }
            return principal.Roles.Contains(Role);
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.HttpContext.Response.StatusCode = 401;
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
            filterContext.Result =
                new RedirectToRouteResult(
                    new RouteValueDictionary(new {controller = "Denied", action = "Index", id = "Unauthorised"}));
        }
    }

This code is not entirely production ready at this point, and I still need to put it through some more tests.

Gary Woodfine
Latest posts by Gary Woodfine (see all)