I recently had the opportunity to do a presentation at the JavaOne 2013 conference in San Francisco. My co-presenter was Shawn McKinney of Joshua Tree Software, the creator of Fortress, the open source RBAC engine. Our talk provided an introduction to ANSI RBAC, and then went on to describe a POC implementation that I did using Fortress. The session was well attended, but for those of you who couldn’t be there at JavaOne this year, I’ll use this post to provide a brief recap of some of my key points from that talk.
The first part of the talk provided an introduction to ANSI RBAC. The slides themselves constitute an excellent summary, and so I don’t need to repeat those points here. The second part of the talk focused on the POC. The security requirement was to add RBAC enforcements to an existing enterprise Web application that was written in Java. Had the application been written using a mainstream application development framework such as Spring, adding the RBAC enablement would have been relatively straight-forward. (As a general rule, though, I only get called on to deal with the really challenging security architecture problems, so I had a feeling that this could not possibly be as easy at it first seemed. There had to be a catch somewhere…).
Well, it turned out that the application did not use Spring Framework or Spring Security. In fact, the application did not use any familiar framework, but rather was written using a proprietary application framework. And it quickly became clear that modifying the source code for this framework was not going to be an option. I had no access to source code for the target applications or framework, and the original application programmer was nowhere to be found… The situation was shaping up to be one of those worse-case scenarios: The business needed to close a known security and compliance gap, the source code was not available, and no framework modifications were going to be possible.
AOP to the Rescue
As described in the presentation deck, the solution to this conundrum was to use Aspect Oriented programming (AOP). As the target system was written in Java, it was possible to use AspectJ to define intercepts for any type or interface in the system. Following the sage advice of David Wheeler, I decided that the best approach would be to add one more level of indirection, and implement AspectJ advice on both the application framework, and the container’s security provider interface.
Specifically, I decided to write a set of AspectJ pointcuts to intercept any calls made to the sensitive resources being managed by the proprietary application framework. This could be done with knowledge of those APIs from the Javadoc for the public API, or even from an application stack trace. A “before advice” would be injected at those primary pointcuts, and this new code would make a call to the container’s security provider. That would both protect those application framework resources with a new enforcement point, and also keep all the security checks centralized through the existing container provider.
Next, I wrote a pointcut on the container security provider interface itself, on the Policy.implies() method. This secondary pointcut would be associated with an “around advice.” This around advice would first call the thisJoinPoint.proceed() method, so that the existing provider could still do it’s job for any resources declared in the application’s deployment descriptor. (It’s important to remember that the container’s security provider is still going to be called though it’s normal invocation path, and not just from the advice we put on the application framework). After the container’s security provider returned from the Policy.implies() method, we would have the opportunity to check to see if the specific resource in question were one of the types that needed to be subjected to RBAC enforcement rules. If so, the advice code would adjudicate an access control decision by delegating the request to an appropriate ANSI RBAC compliant Policy Decision Point (PDP), e.g. Fortress. Whatever the result returned from that PDP (whether “allow” or “deny”), that value would become the container provider’s access control decision. If permitted, the original API request is allowed to continue. Otherwise, I throw an AccessControlException. Since the Java AccessControlException is a runtime (unchecked) exception, all of the existing framework and application code could remain unmodified.
The JavaOne 2013 presentation deck has a nice figure that illustrates this overall solution architecture. And if you’d like to see the end result of all these AOP injections in action, check out this video, which shows a quick demo of the secured application.
The moral of this story is that AOP can be a really valuable tool in the security architect’s tool kit. Using AOP provides excellent support for the principle of Separation of Concerns, and can help to minimize the overall development cost. This technology can be used to add targeted enforcement, even when the source code for the services you are securing is not available to you. And, finally, it is worth noting that this solution is not limited to a specific JEE container. I tested this with Geronimo 3.0.1, but the solution should work equally well with any JSR-115 compliant container.
Update (December 2013)
A recording of this talk is now available.