2

In .NET WebAPI, I've created a way to have all of the authorization rules in a central location, rather than scattered throughout controllers. I'm curious why this centralization isn't done more often; are there repercussions/security concerns?

My current approach is to create a Dictionary during App_Start that contains all of my Authorization data then using a DelegatingHandler to apply the restrictions (code below). The dictionary key is a Tuple of the Controller and Action, and the value is the authorized roles. The DelegatingHandler ties into WebAPI's routing config to get which controller is called, then uses the Dictionary to determine whether the request is allowed.

Dictionary:

var authorizations = new Dictionary<Tuple<string, string>, string>();
authorizations.Add(new Tuple<string, string>("values", "get"), "public");
authorizations.Add(new Tuple<string, string>("values", "put"), "private");

DelegatingHandler:

public class SecurityDelegateHandler : DelegatingHandler
{
    private readonly Dictionary<Tuple<string, string>, string> _authorizations;

    public SecurityDelegateHandler(Dictionary<Tuple<string, string>, string> auth)
    {
        _authorizations = auth;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var config = GlobalConfiguration.Configuration;
        var controllerSelector = new DefaultHttpControllerSelector(config);
        var descriptor = controllerSelector.SelectController(request);

        string restrictions;

        if (!_authorizations.TryGetValue(
                new Tuple<string, string>(descriptor.ControllerName.ToLower(),
                request.Method.ToString().ToLower()), out restrictions))
        {
            return Task<HttpResponseMessage>.Factory.StartNew(() =>
                        request.CreateResponse(HttpStatusCode.Forbidden, 
                        "Access denied on unconfigured actions"), 
                        cancellationToken);
        }

        if (!(Roles.Provider).GetRolesForUser(
               HttpContext.Current.User.Identity.Name).Any(r => 
               restrictions.Contains(r)))
        {
            return Task<HttpResponseMessage>.Factory.StartNew(() => 
                        request.CreateResponse(HttpStatusCode.Forbidden, 
                        "Access Denied"), cancellationToken);
        }

        return base.SendAsync(request, cancellationToken);
    }
}

In summary, my questions are:

  • Are there any problems with implementing Role Based Authorization in this way?
  • Are there any good packages out there that handle centralizing authorization for WebAPI? I've looked into FluentSecurity, but that doesn't appear to support WebAPI.

Thanks!

Hofma Dresu
  • 432
  • 3
  • 13
  • What about making a custom AuthorizeFilter registered as global ? – Réda Mattar Oct 22 '13 at 14:41
  • Using a global filter works, and removes the need for the DelegatingHandler. Still leaves the question of whether there are any problems with using centralized authorization. – Hofma Dresu Oct 22 '13 at 15:53
  • I don't see any problem to that if it suits your needs. Multiple authorization filters are useful if you have different rules for different controllers or actions, but if it's always the same process, you'd better centralize it. – Réda Mattar Oct 22 '13 at 15:58

1 Answers1

2

Your approach is a good one. You should separate concerns. This means separating business logic from non-functional logic/requirements (e.g. logging, authentication, and of course authorization).

The reason why this hasn't been done more broadly is because it's much easier to externalize authentication or logging than it is to externalize authorization which is more related to your business.

Different programming frameworks provide externalized authorization today. Microsoft has claims-based authorization, Java has several frameworks e.g. Spring Security, SunXACML... PHP has Yii, Ruby has CanCan... These frameworks let you implement role-based access control and even attribute-based access control. If you're not familiar with these terms, check out NIST's webpage:

If you want a solution that is technology-neutral, i.e. something you can use for Java, .NET, PHP... you can use XACML, the eXtensible Access Control Markup Language. It's an OASIS standard just like SAML is (SAML focuses on federated id and SSO; XACML focuses on fine-grained authorization). You can read more on XACML on the OASIS website and on Wikipedia where I try to maintain the page. In addition to externalizing authorization, XACML also defines a policy-based approach to authorization which makes a very scalable approach.

There are several open source options (JBoss, SunXACML, OpenAM...) for XACML as well as vendors such as the one I work for, Axiomatics.

HTH

David Brossard
  • 13,584
  • 6
  • 55
  • 88
  • It sounds like XACML is just for *describing* the policy, but you're still going to need something to actually *enforce* it. Nowadays, that would most likely be [OAuth](http://oauth.net/) which seems to be [well-supported](http://stackoverflow.com/a/21858612/268066) in .NET (as well as many other platforms). And OAuth doesn't *need* XACML - The two are orthogonal. – CrazyPyro Oct 14 '14 at 23:41