Using EJB 3 Interceptors for Instance-based Policy Enforcement

A core principle of a good application security architecture is to maintain an appropriate Separation of Concerns.  We need to avoid tangling the code for the application’s business logic, with the code that implements the security enforcements.   In general, the best way to accomplish this is to leverage framework-based enforcement mechanisms whenever possible.  My previous post provided a working example of how to do this in practice, using EJB 3 container-based security with Apache Geronimo.  We showed how to enforce Role-based Access Control for both Web resources and EJB methods, using the standard XML deployment descriptors.  We implemented all of the required security enforcements without making any changes to the actual application code.

Unfortunately, the container-based security enforcement provided by a standard JEE deployment descriptor is limited to protecting object types.  That is, we can easily enforce a policy that says “only tellers may view customer accounts.”  But what if we have a requirement to enforce permissions on specific object instances?  In that case, the declarative approach alone would be insufficient (for one thing, we don’t want to redeploy the application every time a new object instance is created!).  In order to do any type of instance-based policy enforcement, we’ll need to use another mechanism.

Fortunately, EJB 3 also includes the capability to use Aspect Oriented Programming techniques in your application.  A full discussion of AOP techniques is beyond the scope of this post, but the basic idea is that one can inject (at runtime) additional code that implements logic for cross-cutting concerns.  For example, one could add additional logging into an existing set of classes.  Of course, security is my favorite cross-cutting concern, and so in this post I’ll discuss how to use an EJB 3 Interceptor to provide this instance-based policy enforcement.  Because the interceptor is code is completely decoupled from the application code it is again possible to maintain an appropriate Separation of Concerns.  We can add the needed security enforcement logic without impacting the existing business logic.  All we’ll need to do is implement the stand-alone interceptor class, and then wire it into the target application(s) via the deployment descriptor, and redeploy.

How To Do It

There are basically four steps to making this all work:

  1. Implement an interceptor class that will perform the needed security enforcements, and bundle it as a jar file.
  2. Update the application’s EJB deployment descriptor to declare the interceptor class, and bind it to a target EJB class and/or method.
  3. Repackage the enterprise application EAR file to include both the new jar files, and the updated deployment descriptor.
  4. Redeploy the enterprise application.

The following paragraphs provide some additional details on each of these steps.  Note that the complete source code for this example is available over on my GitHub repository.   You’ll want to clone both the psi-jee project (the Pivotal Security Interceptor for JEE), and also the mytime project (the target application).

Implementing the Interceptor Class

I implemented an interceptor that provides an around advice that will examine the values of the arguments passed to the target EJB when it is invoked.  If the values of the calling arguments are consistent with the application security policy, then the call can be allowed to proceed.  If the values of the arguments would violate a security policy, then the user’s request would be denied.  As an illustrative example, consider a hypothetical EJB interface that performs a funds transfer function.  The declarative security enforcements captured in the deployment descriptor could ensure that only users with the right role can access the funds transfer interface.  But only the interceptor will be able to examine the actual values of the parameters passed into the funds transfer method at runtime — these arguments might be String types such as the “FromAccountNumber,” the “ToAccountNumber,” and the “TransferAmount.”  (Of course this is an over-simplified example, but you get the idea).

The interceptor class has an interface contract with just one calling argument, the InvocationContext.  This InvocationContext parameter can be used to obtain the actual arguments that were passed to the EJB that we are in the process of intercepting.  This can be seen in lines 45-47 of the example code.    Of course, the specific EJB arguments returned will vary from one application to the next, but with appropriate knowledge of the application bean(s) you are planning on intercepting, you should know what arguments you need to look for in the params array, and what test(s) to apply.

OK, so now we know what this EJB invocation is trying to do, but we still need to know who is trying to do it.

Since we are running in an EJB container, we can always get a handle to the current EJBContext.  From there we can obtain the currently authenticated principal (the user id).  Looking at lines 73-77 of the code, you can see that I defined a private variable to hold the EJB SessionContext, and then used the getCallerPrincipal() method to find out the userid of the current caller.

Thus, with just a few lines of code we can get access to who is calling the bean method, and what they are trying to do.  Given that runtime context we can then implement whatever security policy checks are appropriate for the business.  If all is well, we call the invocationContext.proceed() method.  Otherwise, we can throw an exception.

Updating the Deployment Descriptors

The new interceptor class must be included in the target application’s deployment descriptor.  This is makes perfect sense, since this is how the EJB container knows that you have defined an interceptor class, and also which EJBs are being targeted by the interceptor.  I won’t repeat the essential snippet of XML here, as it is already captured in the README file of the mytime example that I’ve posted on GitHub.  Of course, the complete deployment descriptor can also be found in the file META-INF/ejb-jar.xml, in the mytime repository.

Repackaging the Target Application

Before you re-package the target enterprise application, you’ll need to make at least one change to the maven POM of your ejb-jar project.

If your target application’s ejb-jar project does not already use the maven-jar-plugin, then you’ll want to add this plugin to the <build>/<plugins> element of the target EJB jar project’s maven POM.  Using the maven-jar-plugin with the configuration as shown will ensure that the MANIFEST.MF file included within the EJB jar will contain a required Classpath: directive.  Basically, you need to have a line in the MANIFEST.MF that tells the container to include the new jar (i.e. the interceptor jar) on the class path of the EJB at runtime.  Take a look inside the EJB jar file after the re-build completes and you should see that the interceptor jar has now been added to that line that says Classpath:  …  psi-jee-1.0.0.jar).

If you’re already using the maven-jar-plugin in this way, then you’ll just need to add the dependency for the new interceptor jar, and the Classpath: value should be updated accordingly.

As noted, I’ve posted all the code for both the interceptor and the target application over at GitHub, so feel free to do a git clone and get started on using EJB 3 interceptors for instance-based enforcements.  Pull requests are always welcome.

Conclusion

While this post has provided specific implementation guidance for an EJB 3 deployment, the real point here is not that we advocating the use of EJB.   Rather, the real take-away is that a good security architect always follows the principle of Separation of Concerns.  Using an interceptor is always good security technique, and fortunately EJB now has support for that.  Security enforcement for object types are delegated to the container.  Security enforcement for object instances are delegated to an interceptor.  The application developer stays focused on the business logic.  The result will be a system that is both more secure, and more maintainable.

If you’re not working in an EJB environment, then this same architectural pattern can still be applied to other containers.  The approach would be similar for, say, instance-based policy enforcements for a RESTful service, accessed over HTTP(S) using a servlet filter deployed to Tomcat, or Jetty.

Finally, if you need to do the enforcements in a container-independent way (perhaps because you need to deploy your application to a number of different containers at runtime), then using an application developer framework such as the Spring Framework with a Spring Security filter chain is clearly the way to go.

Back to the Future: Configuring J2EE Container-based Security

I’ve spent most of the last few years working on security architectures for REST-ful Web Services, using technologies like JAX-RS or Spring MVC.  However, just recently I’ve had a need to go  Back to the Future…I’ve been asked to run some POC experiments with J2EE container-based security.  It’s been both a trip down memory lane, and an opportunity to see some exiting new technologies in action.

For those of you who may not remember the good old days of building EJBs, the basic idea is to architect an application in a classic three-tier deployment model, where the middle or business tier is a collection of Enterprise Java Beans hosted in a J2EE container.  In principal, the business application developer has an easier time of it, since she can delegate all the non-functional overhead of managing transactions, and security, and persistence, etc. to the container….and just focus on coding the business logic.

While there’s still a lot not to like about developing EJBs, they have in fact come along way since I first worked with the technology, way back in 2000.  Remember coding ejbCreate(),  ejbActivate(), ejbPassivate(), and ejbRemove(), all by hand?  Well, EJB 3.0 makes things a whole lot easier.  Really.  Instead of bending code for Mandatory-To-Implement (MTI) interfaces, you can just put the annotation @Stateful or @Stateless on your Java class, and you’re done.

Of course a modern specification like J2EE6 is only really useful when there is an actual container that implements that standard, so it wasn’t long before I needed to choose an actual J2EE server with which to run my tests.  I know a lot of teams who use JBoss successfully, and of course many enterprises use IBM WAS, or Oracle, but I was curious to check out the latest release of Apache Geronimo.  In short, I have been favorably impressed with the 3.0 release of Geronimo.  I found it to be relatively easy to work with, in spite of the limited documentation.  And, after all, it’s open source, so when you are wrestling with a particularly vexing configuration problem, you can just read the source code to see what it is really doing 🙂

Finally, any full application security architecture solution requires that we have a way to manage users, groups, and their corresponding roles, or permissions.  The usual technology of choice for this aspect is Microsoft Active Directory or OpenLDAP.  While searching for an OpenLDAP download for my test environment platform, I happened across IAM Fortress, which is a very cool implementation of ANSI RBAC, built on an OpenLDAP core.  I’ve only just begun to scratch the surface of IAM Fortress, but I’ve been impressed by what I’ve seen so far, and I look forward to blogging more about this little gem in a future post.

So, for anyone who wants to continue this journey down memory lane, and at the same time explore some of the latest in new technology — J2EE, done 2013-style  —  I’ve posted the source code for this POC to my GitHub repository.

Enjoy!   And feel free to issue a pull request 😉