124

I'm reading from several resources (books and SO answers) about authorization in WebApi.

Suppose I want to add Custom Attribute which allows access only for Certain Users:

Case #1

I've seen this approach of overriding OnAuthorization , which sets response if something is wrong

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 public override void OnAuthorization(HttpActionContext actionContext)
  {
   if ( /*check if user OK or not*/)
   {
     actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
   }
  }
}

Case #2

But I've also seen this similar example which also overriding OnAuthorization but with calling to base :

public override void OnAuthorization(HttpActionContext actionContext) 
{ 
  base.OnAuthorization(actionContext);

    // If not authorized at all, don't bother

    if (actionContext.Response == null)  
     {
      //...
     }
}

Then, you check if the HttpActionContext.Response is set or not. If it’s not set, it means that the request is authorized and the user is ok

Case #3

But I've also seen this approach of overriding IsAuthorized :

public class AllowOnlyCertainUsers : AuthorizeAttribute
{
 protected override bool IsAuthorized(HttpActionContext context)
  {
   if ( /*check if user OK or not*/)
   {
    return true;// or false
   }
  }
}

Case #4

And then I saw similar example one but with calling base.IsAuthorized(context) :

protected override bool IsAuthorized(HttpActionContext context)
{
 if (something1 && something2 && base.IsAuthorized(context)) //??
 return true;
 return false;
}

One more thing

And finally Dominick said here :

You shouldn't override OnAuthorization - because you would be missing [AllowAnonymous] handling.

Questions

  • 1) Which methods should I use : IsAuthorized or OnAuthorization ? ( or when to use which)

  • 2) when should I call base.IsAuthorized or base.OnAuthorization` ?

  • 3) Is this how they built it ? that if the response is null then everything is ok ? ( case #2)

NB

Please notice , I'm using ( and want to use ) only AuthorizeAttribute which already inherits from AuthorizationFilterAttribute

Why ?

Becuase I'm at the first stage in : http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

enter image description here

Anyway Im asking via extending Authorize attribute .

Community
  • 1
  • 1
Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • What you need to override the Authorize attribute? What is the usecase you want to achieve? If you need to allow access for certain users why not to use [Authorize(Users="Admin")] attribute like this? – Taiseer Joudeh Oct 20 '14 at 13:08
  • 1
    @TaiseerJoudeh For example Try to authorrize users between 10:00 to 12:00 (configureable). you cant do that with plain Roles and authorized attr. you have to make your own logic – Royi Namir Oct 20 '14 at 13:11

3 Answers3

102

Which methods should I use : IsAuthorized or OnAuthorization ? ( or when to use which)

You will extend AuthorizationFilterAttribute if your authorization logic is not dependent on the identity established and roles. For user related authorization, you will extend and use AuthorizeAttribute. For the former case, you will override OnAuthorization. For the latter case, you will override IsAuthorized. As you could see from the source code of these attributes, OnAuthorization is marked virtual for you to override if you derive from AuthorizationFilterAttribute. On the other hand, the IsAuthorized method is marked virtual in AuthorizeAttribute. I believe this is a good pointer to the intended usage.

when should I call base.IsAuthorized or base.OnAuthorization?

The answer to this question lies in how OO generally works. If you override a method, you can either completely provide a new implementation or piggy back on the implementation provided by parent and enhance the behavior. For example, take the case of IsAuthorized(HttpActionContext). The base class behavior is to check the user/role against what is specified in the filter vs the identity established. Say, you want to do all that but in addition, you want to check something else, may be based on a request header or something. In that case, you can provide an override like this.

protected override bool IsAuthorized(HttpActionContext actionContext)
{
    bool isAuthroized = base.IsAuthorized(actionContext);
    // Here you look at the header and do your additional stuff based on actionContext
    // and store the result in isRequestHeaderOk
    // Then, you can combine the results
    // return isAuthorized && isRequestHeaderOk;
}

I'm sorry but don't understand your Q3. BTW, Authorization filter has been around for a long time and people use it for all kinds of things and sometimes incorrectly as well.

One more thing. And finally there was this guy here who said : You shouldn't override OnAuthorization - because you would be missing [AllowAnonymous] handling.

The guy who said that is the God of access control - Dominick. Obviously it will be correct. If you look at the implementation of OnAuthorization (copied below),

public override void OnAuthorization(HttpActionContext actionContext)
{
    if (actionContext == null)
    {
        throw Error.ArgumentNull("actionContext");
    }

    if (SkipAuthorization(actionContext))
    {
        return;
    }

    if (!IsAuthorized(actionContext))
    {
        HandleUnauthorizedRequest(actionContext);
    }
}

the call to SkipAuthorization is the part that ensures AllowAnonymous filters are applied, that is, authorization is skipped. If you override this method, you loose that behavior. Actually, if you decide to base your authorization on users/roles, at that point you would have decided to derive from AuthorizeAttribute. Only correct option left for you at that point will be to override IsAuthorized and not the already overridden OnAuthorization, although it is technically possible to do either.

PS. In ASP.NET Web API, there is another filter called authentication filter. Idea is that you use that for authentication and authorization filter for authorization, as the name indicates. However, there are lots of examples where this boundary is fudged. Lots of authroization filter examples will do some kind of authentication. Anyways, if you have time and want to understand a bit more, take a look at this MSDN article. Disclaimer: It was written by me.

  • Thanks again , but if I read between the lines , IsAuthenticated is calles by OnAuthirization , so why not override OnAuthorization and call base.OnAuthorization and then check response ? – Royi Namir Oct 20 '14 at 17:04
  • You sure can, if that is what you want. – Badrinarayanan Lakshmiraghavan Oct 20 '14 at 17:14
  • In my third question I meant : after running base function - base.OnAuthorization for example , does the only way to check if it was successful- is to inspect the Response property?, ps the examples are from your book :-) – Royi Namir Oct 20 '14 at 17:16
  • Yes, typically you look for 401 status code but not null, as far as I know. BTW, I don't remember writing about overriding `OnAuthorization` in my book. I'm sure I'd not have written about checking response for null, coz this is the first time I'm hearing about it:) – Badrinarayanan Lakshmiraghavan Oct 20 '14 at 17:34
  • Yes I got confused with the other book. I'm reading 3 books simultaneously : securty(yours) , practical(yours) and webapi pro(Tugberk's, Zeitler,Ali). AS you can see - they did it there : http://i.stack.imgur.com/LNGi4.jpg - they just checked if null , so should i check null or error codes ? – Royi Namir Oct 20 '14 at 17:45
  • Sorry, I'm not sure about what the intention is, with the custom attribute you have shown. If the idea is to just check for a user in one or more roles, you could just use `[Authorize(Roles="Affiliate")]` without any sub-classing. – Badrinarayanan Lakshmiraghavan Oct 20 '14 at 17:58
  • Badri first of all thank you for sharing knowledge and correcting me . Yes i know , but my intention is to know perfectly this custom authorization. Did you see the image in my last comment ? They check if Response is null , but you told me to look if error headers exists . So which way should i go ? – Royi Namir Oct 20 '14 at 18:03
  • Hey, I meant I'm not sure about the intention of null checking response in the custom filter in the book. I took a look at the code you have shown and response is null all the time. – Badrinarayanan Lakshmiraghavan Oct 21 '14 at 04:01
  • Badri Hi , [I found it in your book](http://i.stack.imgur.com/x83HI.jpg) : Why setting the `context.Response` is ending the request ? don't get me wrong , it is , but where is it written ? (docs , code, something ...) ps it relates to my third question ( checking `if (actionContext.Response == null)...`) I also saw it [here](http://stackoverflow.com/a/17317849/859154) - it seems that setting Response, stops ecerything and spit out the response. can you please shed light ? – Royi Namir Oct 24 '14 at 21:14
  • Badri can you please answer my last comment ? – Royi Namir Oct 25 '14 at 06:37
  • Please look at the source code of `ActionFilterAttribute`. https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http/Filters/ActionFilterAttribute.cs. The `ExecuteActionFilterAsyncCore` method checks `actionContext.Response != null` and returns the response thus short-circuiting the pipeline. Only when response is null, it awaits continuation. The best way to understand a framework is to look at the source code. Since frameworks like ASP.NET MVC, Web API (ASP.NET vNext too) are open-source, we are fortunate. – Badrinarayanan Lakshmiraghavan Oct 25 '14 at 06:58
  • You couldn't answer it in a better way. At first sight it was a bit dirty because the thing itself is confusing, but now it's seems to be pretty clear. Thanks a lot. – Leandro Bardelli Mar 30 '15 at 19:46
  • Would you guys check my post here, having trouble implementing this http://stackoverflow.com/questions/35422043/webapi-custom-authorize-attribute-not-working – Luis Valencia Feb 16 '16 at 01:21
  • Hi, you mentioned that `base.isAuthorized` checks the user against the "filter", what is this filter and how do I specify it? – Chara Mar 17 '16 at 14:46
18

Ok, my suggestion is to do the following assuming that you are using OAuth bearer tokens to protect your Web API and you are setting the allowedTime as a claim for the user when you issued the token. You can read more about token based authentication here

  1. Create CustomAuthorizeAttribute which derives from AuthorizationFilterAttribute
  2. override method OnAuthorizationAsync and use the sample code below:

     public class CustomAuthorizeAttribute : AuthorizationFilterAttribute
    {
    
        public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
    
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
    
            if (!principal.Identity.IsAuthenticated)
            {
                return Task.FromResult<object>(null);
            }
    
            var userName = principal.FindFirst(ClaimTypes.Name).Value;
            var userAllowedTime = principal.FindFirst("userAllowedTime").Value;
    
            if (currentTime != userAllowedTime)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Not allowed to access...bla bla");
                return Task.FromResult<object>(null);
            }
    
            //User is Authorized, complete execution
            return Task.FromResult<object>(null);
    
        }
    }
    
  3. Now in your controllers you use CustomAuthorize attribute to protect your controllers using this authorization logic.
Taiseer Joudeh
  • 8,953
  • 1
  • 41
  • 45
  • 1
    Thanks. But I'm currently using `AuthorizeAttribute` which does inherit `AuthorizationFilterAttribute` and -also for learning I specifically asked about which method should I use and about the Response has content or not thingy... – Royi Namir Oct 20 '14 at 14:33
5

ASP.NET v5 Introduced a completely new Authorization System. For those who are going to Use .NET 5 i would suggest moving into Microsoft.AspNet.Authorization.

Pretty much it wraps up the mess caused by keeping both System.Web.Http.Authorize and System.Web.Mvc.Authorize and other older authentication implementations.

It provides a very good abstraction of Action Types(Create, Read, Update, Delete), Resources, Roles, Claims, Views, Custom Requirements and allows to build custom Handlers, combining any of the above. In addition those handlers can be used in combination also.

In ASP.NET v5 authorization now provides simple declarative role and a richer policy based model where authorization is expressed in requirements and handlers evaluate a users claims against requirements. Imperative checks can be based on simple policies or polices which evaluate both the user identity and properties of the resource that the user is attempting to access.

CDspace
  • 2,639
  • 18
  • 30
  • 36
Anestis Kivranoglou
  • 7,728
  • 5
  • 44
  • 47