6

I have taken a look at:

I am trying to test a custom AuthorizeAttribute that I wrote.

I have tried many different things to get it to work. This is my current attempt.

[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]
public class ConfigurableAuthorizeAttribute : AuthorizeAttribute
{
    private Logger log = new Logger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
    private IRoleHelper roleHelper;

    public ConfigurableAuthorizeAttribute()            
    {
        roleHelper = new ADRoleHelper();
    }

    public ConfigurableAuthorizeAttribute(IRoleHelper roleHelper)            
    {
        this.roleHelper = roleHelper;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (!httpContext.User.Identity.IsAuthenticated)
        {
            return false;
        }

        if (this.roleHelper.IsUserInRole(this.Roles, HttpContext.Current.User.Identity.Name))
        {
            return true;
        }

        return false;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);
        filterContext.Result = new RedirectResult("~/home/Unauthorized");            
    }


}
[Test]
public void unauthenticated_user_not_allowed_to_access_resource()
{
    var user = new Mock<IPrincipal>();
    user.Setup(u => u.Identity.IsAuthenticated).Returns(false);

    var authContext = new Mock<AuthorizationContext>();
    authContext.Setup(ac => ac.HttpContext.User).Returns(user.Object);

    var configAtt = new ConfigurableAuthorizeAttribute();
    configAtt.OnAuthorization(authContext.Object);

    authContext.Verify(ac => ac.Result == It.Is<RedirectResult>(r => r.Url == ""));
}

No matter what I do I always get a System.NullReferenceException when I run the test. It never seems to get past the OnAuthorization call. The stack trace is as follows:

Result Message: System.NullReferenceException : Object reference not set to an instance of an object. Result StackTrace: at System.Web.Mvc.OutputCacheAttribute.GetChildActionFilterFinishCallback(ControllerContext controllerContext) at System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext) at ...ConfigurableAuthorizeAttributeTests.unauthenticated_user_not_allowed_to_access_resource() in ...ConfigurableAuthorizeAttributeTests.cs:line 29

Does anybody have any ideas on how to solve this problem?

Edit

I found the solution. I also needed to mock ControllerDescriptor and make sure that HttpContextBase.Items returned a new Dictionary.

Working code:

var context = new Mock<HttpContextBase>();
context.Setup(c => c.Items).Returns(new Dictionary<object, object>());
context.Setup(c => c.User.Identity.IsAuthenticated).Returns(false);
var controller = new Mock<ControllerBase>();

var actionDescriptor = new Mock<ActionDescriptor>();
actionDescriptor.Setup(a => a.ActionName).Returns("Index");
var controllerDescriptor = new Mock<ControllerDescriptor>();            
actionDescriptor.Setup(a => a.ControllerDescriptor).Returns(controllerDescriptor.Object);

var controllerContext = new ControllerContext(context.Object, new RouteData(), controller.Object);
var filterContext = new AuthorizationContext(controllerContext, actionDescriptor.Object);
var att = new ConfigurableAuthorizeAttribute();

att.OnAuthorization(filterContext);

Assert.That(filterContext.Result, Is.InstanceOf<RedirectResult>());
Assert.That(((RedirectResult)filterContext.Result).Url, Is.EqualTo("~/home/Unauthorized"));
Community
  • 1
  • 1
pkidza
  • 419
  • 4
  • 12
  • `home/Unauthorized` allows anonymous? check in web.config – Murali Murugesan Oct 11 '13 at 09:17
  • Which line is no. 29? – Henk Mollema Oct 11 '13 at 09:21
  • I wouldn't think that would make a difference as I am mocking everything? The site is not deployed anywhere and I am directly calling my Attribute class methods. I removed base.HandleUnauthorizedRequest(filterContext); just in case but I still get the exception. – pkidza Oct 11 '13 at 09:26
  • Line 29: configAtt.OnAuthorization(authContext.Object); – pkidza Oct 11 '13 at 09:26
  • Then either `configAtt` or `authContext.Object` are null. Check you check on that? – Henk Mollema Oct 11 '13 at 10:16
  • @HenkMollema I found the answer. The first thing I had to do was make sure that HttpContextBase returned a new instance of Dictionary. That got rid of the Exception but I was still getting another NullReferenceException. I then worked out that I needed to mock ControllerDescriptor. – pkidza Oct 11 '13 at 11:20
  • Welcome to Stack Overflow! Almost all cases of `NullReferenceException` are the same. Please see "[What is a NullReferenceException in .NET?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-in-net)" for some hints. – John Saunders Oct 13 '13 at 02:20

1 Answers1

12

I found the solution. I also needed to mock ControllerDescriptor and make sure that HttpContextBase.Items returned a new Dictionary.

Working code:

var context = new Mock<HttpContextBase>();
context.Setup(c => c.Items).Returns(new Dictionary<object, object>());
context.Setup(c => c.User.Identity.IsAuthenticated).Returns(false);
var controller = new Mock<ControllerBase>();

var actionDescriptor = new Mock<ActionDescriptor>();
actionDescriptor.Setup(a => a.ActionName).Returns("Index");
var controllerDescriptor = new Mock<ControllerDescriptor>();            
actionDescriptor.Setup(a => a.ControllerDescriptor).Returns(controllerDescriptor.Object);

var controllerContext = new ControllerContext(context.Object, new RouteData(), controller.Object);
var filterContext = new AuthorizationContext(controllerContext, actionDescriptor.Object);
var att = new ConfigurableAuthorizeAttribute();

att.OnAuthorization(filterContext);

Assert.That(filterContext.Result, Is.InstanceOf<RedirectResult>());
Assert.That(((RedirectResult)filterContext.Result).Url, Is.EqualTo("~/home/Unauthorized"));
pkidza
  • 419
  • 4
  • 12