Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing a custom Web API AuthorizeAttribute

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.

like image 723
Darren Wainwright Avatar asked Jun 06 '17 17:06

Darren Wainwright


1 Answers

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.

like image 72
Nkosi Avatar answered Oct 12 '22 02:10

Nkosi