10

I am trying to unit test, with NUnit in C#, a custom Authorize Attribute. In particular that a particular http status code and message have been returned in the case of not being authorized.

My attribute is super simple - looks like this:

public class AuthorizationAttribute : AuthorizeAttribute
{

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if (IsAuthorized(actionContext))
            return;

        HandleUnauthorizedRequest(actionContext);
    }

    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "You are not authorized to access this resource");
    }
}

So to test this (and currently new in the field of testing) I have cobbled together the following code. In it, i am attaching a generic identity with a username and some role data.

public void Given_UserIsNotInAuthorizedRoles_When_Auhtorizing_ReturnsForbidden()
{

    // Arrange

    IPrincipal principal = new GenericPrincipal(new GenericIdentity("TestName"), new[] { "TestRole" });

    HttpActionContext mockActionContext = new HttpActionContext()
    {
        ControllerContext = new HttpControllerContext()
        {
            Request = new HttpRequestMessage(),
            RequestContext = new HttpRequestContext() { Principal = principal }
        },
        ActionArguments = { { "SomeArgument", "null" } }
    };

    mockActionContext.ControllerContext.Configuration = new HttpConfiguration();
    mockActionContext.ControllerContext.Configuration.Formatters.Add(new JsonMediaTypeFormatter());

    // Act
    AuthorizationAttribute authAttr = new AuthorizationAttribute();
    authAttr.OnAuthorization(mockActionContext);

    // Assert
    Assert.IsTrue(mockActionContext.Response.StatusCode == System.Net.HttpStatusCode.Forbidden);

}

The mock controller looks like this:

[Authorization(Roles = "AdminRoleOnly", Users = "A user")]
internal class MockController : ApiController { }

When I'm debugging, i am finding that if (IsAuthorized(actionContext)) is returning true - which i don't understand.

Can someone point me in the direction of why my authorize attribute is passing this identity as good?

For what it's worth, this code works in production. I'm back-filling some tests.


Somewhat related, are these ones

I've read through the question and answer on a similar question ASP.NET MVC unit testing custom AuthorizeAttribute though neither really either work nor relate, especially given they're for MVC controllers and not Api Controllers.

I've also read and tried to implement the code in the answer on this question too Mocking HttpActionContext.ActionArguments when testing Web.Api ActionFilter


The latter gets me somewhere near in that my authorization attribute is firing in a test and I am able to pass in the required context information.

6
  • Which beavior are you expecting? if (IsAuthorized(actionContext)) is returning true it means that the mockActionContext you provide is valid :) Any idea of what happens in the IsAuthorized function? Commented Jun 6, 2017 at 17:17
  • I expect IsAuthorized to return false. My principle has different roles from the mocked controllers AuthorizeAttribute. My principle is Authenticated, which is different though. The IsAuthorized method i'm calling is in the base of AuthorizeAttribute. MSDN says it just Indicates whether the specified control is authorized. which i understand to happen based on roles etc. Commented Jun 6, 2017 at 17:21
  • Take a look at what is happening in the source code for IsAuthorized Commented Jun 6, 2017 at 17:24
  • @Nkosi - thanks. Then why, if i remove the principle altogether does it not return false? It should return false on the first if Commented Jun 6, 2017 at 17:28
  • 1
    @zeroflaw You probably got it sorted, but for those running in to the same issue- make sure that the response object on the context isn't null :) Commented May 3, 2019 at 13:39

1 Answer 1

3

You need to assign a Role to the AuthorizationAttribute. In your example you have a TestRole assign to the principal. Assign any other role but that.

// Act
AuthorizationAttribute authAttr = new AuthorizationAttribute() {
    Roles = "SomeOtherRole"
};

and the test should behave as expected when exercised.

If you review the source code for IAuthorized You will see logic that checks if there are roles assigned to the attribute. If there are none to compare it will default to true.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.