On my current project we were recently faced with an interesting security issue. The heart of the problem was that we had a set of secured EJB 3 services that needed to be called from a jBPM engine in the same container that for various reasons was not in a security domain. Here I'll go over the way we chose to solve the issue and show some snippets of the "proof of concept" unit test.

The solution we eventually came to involved using an EJB 3 interceptor to inject a custom system principal around any BPM "actions" that needed to call secure services. This approach allows the interceptor to be reused for any unsecured system components and is configuration driven, as we'll see later.

To test this I threw together some stateless EJBs and a JUnit 4 test. First, the secured service, complete with RolesAllowed annotation:

@Stateless
public class SecuredService implements SecuredServiceRemote
{
 @RolesAllowed("SecuredServiceRole")
 public void doItSecurely() {
 log.info("made it!");
 }
}

This service is in a security domain.

Next I created another EJB to represent the jBPM action classes, which are just stateless beans themselves. Note that this is an unsecured bean:

@Stateless
public class FakeActionService implements FakeActionServiceRemote
{
 @EJB
 SecuredServiceRemote securedService;
 
 @Interceptors(SystemAuthenticatorInterceptor.class)
 public void doIt() {
 securedService.doItSecurely();
 }
}

Note the @Interceptors annotation — SystemAuthenticatorInterceptor is where we'll do the system principal injection. Exactly which principal to use is based on the name of the calling method or, for a more coarse-grained approach, the entire class. So in essence, each system component can be configured to have a specific role associated with it:

@AroundInvoke
public Object authenticate(InvocationContext context) throws Exception
{
 // ...
 // Some String manipulation to get the calling method and class
 // ...
 
 // first check for specific methods
 String prin = getFromConfig(callingMethod + ".principal");
 String pass = getFromConfig(callingMethod + ".password");
 // ...and perhaps decrypt the password
 
 if(StringUtils.isBlank(principal) || StringUtils.isBlank(password)) {
 // no method level configs found, so check for class level
 String prin = getFromConfig(callingMethod + ".principal");
 String pass = getFromConfig(callingMethod + ".password");
 
 if(StringUtils.isBlank(principal) || StringUtils.isBlank(password)) {
 // appropriate log message
 return context.proceed();
 }
 }
}

Assuming we found a configuration entry for the calling class or method, we now set it using a JBoss class, org.jboss.security.SecurityAssociation:

// found a config entry, set it
SecurityAssociation.setPrincipal(new SimplePrincipal(prin));
SecurityAssociation.setCredential(pass.toCharArray());

And finally, a simple JUnit test to play the part of jBPM engine and kick the whole thing off:

@Test
public void testSystemAuthInterceptor() throws Exception {
 service = new FakeActionServiceDelegate();
 service.testIt();
}

To apply this pattern going forward we'll simply need to add the interceptor to any unsecured system components that will need to call secured services. We'll also need to add configuration entries for the roles we want associated with the components.