Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting Result in the context of ChallengeAsync method in an authentication filter

This question is related to the answer I have provided here. OP's comment got me thinking a bit. I suggested using a class implementing IHttpActionResult like this in the ChallengeAsync method of the authentication filter.

public Task ChallengeAsync(HttpAuthenticationChallengeContext context,
                                  CancellationToken cancellationToken)
{
    context.Result = new ResultWithChallenge(context.Result);
    return Task.FromResult(0);
}

public class ResultWithChallenge : IHttpActionResult
{
    private readonly IHttpActionResult next;

    public ResultWithChallenge(IHttpActionResult next)
    {
        this.next = next;
    }

    public async Task<HttpResponseMessage> ExecuteAsync(
                                CancellationToken cancellationToken)
    {
        var response = await next.ExecuteAsync(cancellationToken);
        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            response.Headers.WwwAuthenticate.Add(
                   new AuthenticationHeaderValue("Basic", "realm=localhost"));
        }

        return response;
    }
}

Instead of this, I can simplify the ChallengeAsync like this.

public Task ChallengeAsync(HttpAuthenticationChallengeContext context,
                             CancellationToken cancellationToken)
{
    var result = await context.Result.ExecuteAsync(cancellationToken);
    if (result.StatusCode == HttpStatusCode.Unauthorized)
    {
        result.Headers.WwwAuthenticate.Add(
                     new AuthenticationHeaderValue("Basic", "realm=localhost"));
    }
    context.Result = new ResponseMessageResult(result);
}

This saves me from creating a class implementing IHttpActionResult but is this the right way? I get an uneasy feeling that this is somehow bad from a performance standpoint because it feels like I'm converting action result to HttpResponseMessage and back to action result. Any pointers on the need for a separate class here implementing IHttpActionResult like what I suggested will be appreciated as against using the code above.

like image 723
Badri Avatar asked Feb 12 '14 15:02

Badri


People also ask

How do you implement an authentication filter?

To apply an authentication filter to a controller, decorate the controller class with the filter attribute. The following code sets the [IdentityBasicAuthentication] filter on a controller class, which enables Basic Authentication for all of the controller's actions.

When creating a new authentication filter what base classes interfaces should be derived from?

To create a custom authentication filter in ASP.NET MVC, we need to create a class by implementing the IAuthenticationFilter Interface. This IAuthenticationFilter interface has 2 methods.

How do I use authorization filter in Web API?

Web API provides a built-in authorization filter, AuthorizeAttribute. This filter checks whether the user is authenticated. If not, it returns HTTP status code 401 (Unauthorized), without invoking the action. You can apply the filter globally, at the controller level, or at the level of individual actions.

How does authentication and authorization work in Web API?

The authentication and authorization mechanism in such a site is simple. After the user logs into the website, a single database holding user information verifies their identity. A session is created on the server, and all subsequent requests use the session to identify the user without another login required.


1 Answers

The intent was to use the first approach rather than the second. For example, see the Basic Authentication sample (also available for MVC), which follows the first approach: http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/BasicAuthentication/ReadMe.txt

The second approach mostly works. I wouldn't be too concerned about the performance standpoint; either way you're allocating one action result object and one response message object, so I'm not seeing much difference there.

However, there are a couple of reasons I'd recommend the first approach:

  1. The second approach won't work the same way in MVC. Both MVC and Web API have authentication filters, and they basically work the same way. But in MVC, there isn't an equivalent to ResponseMessageResult (the HttpContext is updated as needed, rather than returning a HttpResponseMessage that could be replaced by each caller going up the stack). If you have an MVC implementation of your authentication filter, you'd likely end up doing the first approach there anyway.
  2. It slightly changes the pipeline behavior from what's intended. The code in ChallengeAsync runs earlier than the code in the context.Result that it returns. For example, if the code changed a property on the HttpRequestMessage and that impacted a later filter's ChallengeAsync logic, the behavior could be different than what's intended.

The framework definitely could make it easier to implement the interface; feel free to vote on this work item: https://aspnetwebstack.codeplex.com/workitem/1456

like image 106
dmatson Avatar answered Oct 10 '22 04:10

dmatson