Authorize attribute not working with Windows Authentication application

3.7k views Asked by At

I have an MVC4 application whereby I have assigned roles to my user using a custom role provider so that when I check User.IsInRole against my User table it determines which links etc to display on screen in my _Layout.cshtml page. This is working on the Layout page in that the correct links are appearing.

However when I secure my Admin controller using the

[Authorize(Roles = "Admin")]

I am getting the following stack trace from an object not set to instance of an object error:

[NullReferenceException: Object reference not set to an instance of an object.]
System.Web.Mvc.AuthorizeAttribute.AuthorizeCore(HttpContextBase httpContext) +39
System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext) +159
System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) +96
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__1e(AsyncCallback asyncCallback, Object asyncState) +446
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +302
System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__17(AsyncCallback asyncCallback, Object asyncState) +30
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +382
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +317
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +15
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__2(AsyncCallback asyncCallback, Object asyncState) +71
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +130
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +249
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +50
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +16
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +301
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

What exactly is in this Filter context? This works without any further configuration when I use ADFS or Forms based authentication but when using Windows based authentication I have had to do the following to get IsInRole method working:

this.UserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

if (this.UserName.Contains("\\"))
{
  string[] stringArray = this.UserName.Split(new Char[] { '\\' });
  this.UserName = stringArray[1];

  MyUser identity = userRepository.Get(u => u.Username == this.UserName).FirstOrDefault();
  HttpContext.Current.User = identity;
}

Do I need to configure some other HttpContext proper in order for Authorize attribute to work in same manner as IsInRole method?

1

There are 1 answers

10
Mike Beeler On

In the forms case, it could be anything but it is very common to implement a username password form with a lookup by username in a user table, based on the code presented it looks like the repository expects just a username, it just turns out that windows.identity.name returns domain\user. That's where the extra effort comes in to split into domain, user. example below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication6
{
    public class DemoAuthAttribute : AuthorizeAttribute
    {
        // create a file like auth.cs in the mvc project 
        // called 
        //    [DemoAuth("BAR")]
        // as an attibute on a controller method

    private string _role;

    public DemoAuthAttribute(string role)
    {
        _role = role; // should be exapanded to handle more than one
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        return httpContext.Request.IsAuthenticated &&  _role == "FOO";
        // lookup the current user in database does the user have role as specificed by the attribute?
        // if yes sucess if not fail.
    }
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (AuthorizeCore(filterContext.HttpContext))
        {
            // your custom logic here
            string text = string.Format("<u><h5>Auth successfull.....</h5></u></br>");
            filterContext.HttpContext.Response.Write(text);
        }
        else
        {
            // RedirectResult, etc.
            string text = string.Format("<u><h5>Auth unsuccessfull.....</h5></u></br>");
            filterContext.HttpContext.Response.Write(text);
        }
    }

}

}