When we think about authorization, we often think users, roles, and permissions. Essentially, what a user can do in a system usually boils down to a simple formula:
Role X has Permission Y
John has Permission Y
And while this role-based model is effective, intuitive, and easy to implement, unfortunately, in most enterprise applications, it isn’t enough – there are some portion of authorization requirements that can’t be neatly codified in simple user-role-permission relationships.
In this post, I’d like to take a stab at defining some of the tricky (but common) authorization requirements that stretch the boundaries of basic role-based access control. My hope is that by identifying (and putting a name to!) these different types of authorization rules, we’ll be in a better position to determine the authorization solution that best fits our needs – whether it’s a simple role-based approach or a complex policy engine (e.g Oracle Entitlements Server, Cisco’s Policy Manager, etc.).
Ok, here goes…
Beyond roles, authorization rules often needs to consider some attribute of the person to determine whether they have access (see ABAC). For example, if the requirement is: “only customers in the Pittsburgh region can approve a document”, then a customer’s region would be a relevant subject attribute to the authorization rule.
Attributes can be one-dimensional, in which case they can easily be encoded as simple roles (e.g. a user from the “Pittsburgh” region could be put in a “Pittsburgh” role). When multiple attributes come into play, however, things get tricky. For example, if both “region” and “customer priority” are relevant attributes, then encoding these in terms of roles would yield a messy combinatorial cross-product:
This obviously gets untenable from an administration perspective – i.e. what happens when we add a new region? Or a new attribute? For this reason, subject attributes typically need to be managed outside of roles.
Object AttributesOn the flip side, attributes of the object of an action can also be relevant to an authorization decision. For example, if the requirement is “a customer can only view his own bill”, the system would need to verify that the object being acted upon (the bill) belongs to the subject (the customer). Roles won’t even come close to helping you with this type requirement!
To make things more complicated, sometimes object attributes and subject attributes need to correlate – for example “only customer service reps from the Pittsburgh region can remove charges from customers from Pittsburgh” (see above). In this case, the subject attribute (customer service rep’s region) needs to match the object attribute (customer’s region).
Some authorization rules transcend binary permit/deny decisions; they instead state that results of a request be filtered to only those rows a user is authorized to view. For example, perhaps a doctor querying a patient database should only be shown those patients for whom he’s had contact, and hide the others. Or “users from San Francisco can only view customers from San Francisco”. I touched on this distinction between access control and filtering a bit more in a previous post.
Column-level FiltersSimilarly, it can be necessary to restrict a specific column (or field) for certain users. For example, it may be the case that customer service reps may not view a customer’s SSN, but a manager may.
User Interface Show/Hide
Protecting an action by itself is sometimes not enough – we often want to prevent a user from trying to invoke it altogether. For example, if a user doesn’t have access to delete an account, then a “delete” button shouldn’t be displayed on the UI. This is something that , as developers, we often forget – we assume that by protecting the service boundaries (urls, service operations, etc.) we’ve done enough, until we talk to users and they ask “if I’m not able to delete an account, why do you even give me the option?”. Ugh.
To make matters more difficult, the logic that protects the action should ideally be the same logic that controls whether the button is shown or hidden – duplicating the logic in the client and server layers would be sub-optimal.
Resources or actions can also be restricted based on the date or time – for example, “users can only submit requests during business hours of 8am-6pm” or “users can only approve documents after the 15th of the month”.
There are times when a permission for a user should expire after some period of time – for example, “Joe has the permission to do X, but only for the next week”. These are similar to date/time rules, but subtly different.
Similarly, it is sometimes necessary to transfer one user’s permissions to another. For example, “Bob will be gone on vacation for 3 weeks, so delegate all his permissions to Ed”. In a simple role-based model, this is relatively trivial – just copy roles from Bob to Ed. When using attributes, however, it can get a little trickier.
Hierarchies and Inheritance
For easier administration, roles can be organized in hierarchies, such that the permissions of a parent role are inherited by a child role – e.g. “a super admin can do everything that an admin can do, plus X, Y, and Z”. Similarly, resources can also be organized hierarchically, e.g. “the admin can access any page under /admin/”.
In some cases, it’s imperative for one user to enter a a system as another – similar to the “sudo” command. For example, it might be helpful for a customer service rep to be able to log in as a customer, in order to see exactly what the customer sees, and help debug problems. To complicate things, the customer service rep might only be able to view while logged in as the student, but not update any data.
As you can see, authorization rules come in a variety of flavors, and it’s important to understand which your business needs, so that you can design/implement an appropriate solution. Implementing an ill-suited authorization framework, or as is more common, just implementing authorization logic as custom application code, will be a big problem later on in terms of complex, unmaintainable code, difficult administration/provisioning, and incomplete auditing and reporting.