What is Authorization and why should it be externalized?
In our dynamic world, yet another common wisdom has turned out to be a rather common unwisdom: how to treat authorization in your code. This article discusses what authorization means for the developer, and what you can gain by externalizing it.
What exactly is authorization? Authorization in a nutshell is making sure that users can access those things that they should, and cannot access those things that they shouldn't have access to. Unfortunately many confuse this with authentication, which is making sure that people are really who they say they are. Of course, once you establish who somebody is, you can look up details about the user, and use those details in order to control access.
Authorization happens at many place within code, in different layers and with different granularities. The simplest form of authorization is coarse-grained, and is at the level of making a decision on whether a particular user should have access to a particular application. This could be a very simple rule, i.e. "if you have a valid account, then you can get in". Once a user is in the application however, what should he or she be able to do? This is where fine-grained authorization takes place.
Think about an application that allows a user to view customer orders. Which orders should a user be able to see? Perhaps when dealing with a sales associate, orders can be displayed for the shop where the associate is working. Or perhaps when the user is one of the sales staff "on the road", the only orders that should be viewable are the ones that the associate has personally closed. Or perhaps the orders that have been taken by the associate's team? Or the ones in the region? Or think of a service that fetches this data and makes it available. What part of the data should be returned in order to make sure that the requestor will only see the data that he or she is entitled to see?
To make things even more sophisticated, think of a distributed or multi-tiered application, or even a service-oriented architecture, or a cloud service. Suddenly, authorization needs to be done on every layer, every tier, - in fact in every bit of code that is involved. Keeping that under control is not an easy job - especially when code is being written to make decisions. When multiple pieces of the puzzle are written by many different teams, it takes a whole lot of work making sure everything is aligned in terms of access control. In a perfect world, access control in all parts of the application will work smoothly together. However, the world is not perfect - as you know - and problems can arise if application security is not properly handled by experts.
In order to make our lives as developers easy we take the sensible route of moving similar, often-used code to a layer of its own. This allows us to save time by calling the layer instead of having to write custom code over and over again. For authorization, a little bit of this has actually happened, but only in a very limited way. We're still writing fine-grained authorization code. It's all over the place in our code, and this is bad.
Every since the term "Identity Management" was coined, people have looked for a way to formally manage users and entitlements that would ultimately grant users access to systems and functions. Identity Management technologies are used to provision and manage users, roles and entitlements to target systems. This allows a administrator to control access on a coarse scope. Users who have a particular role or are in a particular group may access certain parts of a system and so on.
While the Identity Management industry as a whole has figured out how to simplify access management for managers and auditors, things doesn't look so rosy for the developer. The common "wisdom" is that fine-grained authorization should be done within applications - meaning, with code. This can't be good - you have probably learned again and again that it is usually a bad idea to hardwire things into your code that could (or rather should) otherwise be configured externally. For example, if you develop in Java, chances are high that you'll use log4j for all of your logging needs. This allows you to externalize logging configuration and provides you with a quick and easy to use API for logging. So why should this be any different for authorization?
The reason is most likely because there are many different programming patterns for authorization. There are actually some frameworks for coarse-grained authorization. These are usually based on the concept of roles, which is why they implement a form of the RBAC model (Role-based Access Control). Yet, for fine-grained authorization they are not usable. This is where XACML comes in - a policy language that defines authorization on any level - coarse and fine-grained.
Here are some of these programming patterns for authorization patterns. A very coarse-grained example is to look at the role or group membership of a user and then to decide whether that user has access to a particular function. This is very easy to do, and is even provided by frameworks such as JAAS or Spring. But once the user has been let in, what is the user allowed to do? Take the case that the user is presented with a form filled with different UI components. Some of these should possibly be disabled (or hidden) because the user may not have the privilege to interact with them. For example, some information may not be edited, or some buttons may not be clicked. To make these decisions means that you have to take into account some particular data that you have in the application. For example in the case of a sales associate looking at orders - perhaps the order may not be edited because it has been closed? In this case you need to take into account the order status of the current order.
When you externalize authorization, you therefore need to call an external layer, and pass all of the relevant information. In a XACML-enabled system, you can do this with ease. XACML is based on Attribute Based Access Control (ABAC). This means that you can use any combination of attributes (not just the "role" of a user, as in RBAC) to make decisions. In the code, you could therefore call the authorization layer to authorize every UI component, and pass in all of the information that you know about the user, the current function, and the record that is being displayed. In a similar way you can authorize data that is displayed, or searched for.
And how is the authorization layer implemented? The obvious choice for authorization - from coarse to fine-grained - is with the XACML standard. XACML is based on ABAC and is therefore very flexible. XACML defines an architecture, policy language and a request/response format. APIs are available for several languages, and the deployment model is versatile. Another advantage is that XACML APIs do not get in your way when you develop, and can potentially save a lot of time, just like other frameworks that move into a separate layer those pieces of code that you would otherwise have to write over and over again.
How much time? Axiomatics customers report savings of anywhere from 15-30% of time from their XACML deployments, including on-boarding of new applications. Authorization is typically deeply engrained within the code, and moving it to a separate layer gives many other benefits apart from saving code and development time: authorization policies can be changed outside of the application without changing code, security audits become easier, and policies can be imposed across applications, or individual services.
Authorization can and should be externalized. The only reason why people still follow the bad practise of hard-coding it in application code is because they do not know how it can be done. The good news is that this information is available, and we at Axiomatics are happy to share our and our customers' experience with you for you to see yourself what a game-changer externalized authorization is. Interested? You will find the information that you are looking for here on our Developer's Corner.