There’s plenty of talk about security and SOA (or should I just say services now?), but the vast majority seems to cover only the issues of authentication and identity management, and neglects the equally important problem of authorization (*1). Although I can't claim to be a security expert, in a series of posts, I’d like to share some of my thoughts and experiences on implementing authorization in the world of service-oriented architectures.
In this first post, I’d like to take a quick trip through some of the basic terms and definitions of authorization, laying the conceptual groundwork for the later posts. Ok, let’s get started!
Access Control Policies
In general terms, an authorization or access control policy defines whether a given subject can perform an action on a particular object. For example, a policy could determine whether "Hines Ward" (subject) can delete a charge (action) from "Mike Tomlin's" account (object). (*2) This decision, to grant or deny access to a specific object or resource, is commonly based on one or more the following four factors:
- Role-based (RBAC): Most often, access to a particular operation is granted by virtue of a specific role that a subject is affiliated with. For example, the ability to remove a charge could be granted to any user with an "Account Admin" role.
- Attribute-based (ABAC): Access control may also be based on some inherent attribute of the user or object. For example, Account Admins from the Northeast region (user attribute) may remove charges from customers from the Pittsburgh district (object attribute). In this way, access control policies define a relationship from subject to object that must exist in order to perform the action.
- Consumer-based: In an SOA world, service endpoints may be open to the network, and so it may be necessary to manage access to an operation based on the consumer of that service. For example, ensure that only the Customer Service may invoke operation "getAccountInfo(customerId)" on the Accounting Service.
- Time-based: It is sometimes necessary to restrict access to a particular resource based on the time of day or calendar date - for instance, "only allow changes to accounts during normal business hours, 8am - 5pm".
Access vs. Filtering
Beyond the subject-action-object form of access policy defined above, there's another type of authorization that's just as crucial in enterprise applications: response filtering. Although both types are based on the authorization factors defined above (role, attribute, consumer, time), filtering policies determine not whether a user be restricted to a specific operation on an object, but rather that the data that is retrieved from an operation be narrowed to only those records or fields that the subject is authorized to view . For example, when user "Hines Ward" of the "Pittsburgh" region calls operation "fetchAccounts()", the system can allow access, but return only those account records for customers in the "Pittsburgh" region, and not account records for customers in other regions.
In my experience, these two types of authorization ("access" and "filtering") are often mistakenly conflated, and so are assumed to be satisfied by the same authorization framework. Unfortunately, this isn't usually possible - a framework or solution that protects access to a resource (e.g. URL, endpoint, etc.) is fundamentally different than one that filters result sets or message bodies. It's important, therefore, to identify the type of authorization requirements that exist to guide downstream design.
Architectural Components of Authorization
Having trudged through some of the conceptual territory of authorization, we can now dig into some of the tangible, implementation details. In any authorization solution, most of the following architectural entities exists in some form or another, though they may not be clearly abstracted:
- Policy Definitions: Where policies are actually defined and stored. In the case of simple RBAC models, this may just be a database managing relations between users, roles, and entitlements, but in more complex ABAC models, these could be separately defined policy files (e.g. XACML). Note that policies are also quite often found "hard-coded" in business logic or UI code (e.g. "if(user.group == 'admin') showButton()"). (*3)
- User Store: The central repository for core user information (e.g. name, id, etc.) - think LDAP for enterprise apps, or perhaps just a "user" table in a RDBMS for smaller apps.
- Attribute Store (i.e. Data): As I defined it in the section above, authorization attributes (whether subject or object) are just plain old business data that happens to be relevant to determining access for a user. For instance, in the example above, the customer's region is a relevant authorization attribute, and would likely just be stored as a "region_id" column on the "customer" table.
- Policy Enforcement Point (PEP): The place in the architecture that enforces access control. For example, in a simple web-application, this could be a servlet filter that protects the resource.
- Policy Decision Point (PDP): The place in the architecture that makes access control decisions. Note, in smaller applications, this likely is the same as the PEP, but in larger, distributed applications, it could be different. Also, note that in some cases Policy Definitions are embedded within the Policy Decision point, but may be externalized (e.g. XACML).
- Response Filter: The entity responsible for winnowing a data set down to only those records a user is authorized to view.
A "Simple", non-SOA Example
Already, authorization seems a little harrowing - and we haven't even gotten to SOA yet! Before we do, as a final step toward laying the authorization groundwork, let's map some of the concepts and architectural elements defined above to territory that's most likely familiar - a simple, stand-alone web application.
As the diagram above illustrates, authorization in this "simplest" case can still be rather complex. Policy definitions and decision points are scattered throughout the different layers of the architecture - an interceptor responsible for protecting resources (i.e. URLs) based on roles, the UI for showing/hiding information based on permissions, the business logic for executing complex, attribute-based authorization decisions (e.g. customer can only view their own account), and the data access layer (or database) for filtering data sets to only those records the user is authorized to view. The database stores user, role, permission, and attribute data, queried by the different PDPs.
What's Different in SOA?
As I've written about before, SOA puts a new twist on old problems, and it's the same for authorization. What was a delicate but well-traversed and tractable issue before, is an extremely complex and risk-ridden problem when you stir in the ingredients of a SOA-based enterprise architecture - loosely-coupled services, registries, process engines, stand-alone user interfaces, ldap directories, etc. Although I'll cover these pitfalls in future posts, here are a few monkey-wrenches SOA throws into the authorization machine:
- Is there a central repository for all users of an enterprise?
- Is there a central repository for roles and permissions for all services in the enterprise? If not, does each service maintain its own unique set of roles and permissions for users?
- How are authorization attributes propagated between services?
- Can policies be managed centrally, such that changes to access control necessitates only going to one place, and not to every individual service?
- What happens when a policy depends on retrieving data that is not local to the service it resides in? In other words, can policies call other services to retrieve authorization attributes they need to make allow/deny decisions?
- How can a service ensure that only other services call it?
- To what extent can policies be modified at run-time? How can they be managed?
And this is just the tip of the iceberg! In my humble opinion, most of these issues boil down to the same central vs. local diametric decision - i.e. what authorization components should be centrally shared by all services (e.g. User store/service, etc.) and which should be locally (read: redundantly) defined, within each service. Obviously, there are major trade-offs on both sides - performance, maintainability, scalability, and reliability to name just a few.
To sum up, I hope I was able to lay some of the building blocks of authorization. In later posts, I'd like to touch on different approaches, patterns, products, and standards for authorization in SOA. I'd love to hear what you think so far, so please feel free to drop me a comment!
1. For those people who get these mixed up (I used to be one!), authentication tackles the problem of verifying that the user is who he says he is, and identity management with the multi-faceted problem of how users are given identities and how these identities are propagated. Authorization, on the other hand, assumes these first two issues are solved, and deals with ensuring that a user may do only what he has permission to do.
2. Yup, I'm a Steeler fan:)
3. The dividing line between "business logic" and "authorization policy" is often fuzzy - and it's not always clear whether a requirement should be implemented within the confines of the authorization framework, or whether it can be happily embedded within normal business logic code. In an email comment from Rick, he suggested that a good litmus test is the requirements around manageability - e.g. who is responsible for managing access rights, does the logic need to be configurable at run time, etc. I think this is a great point.