I have an application in which some operations are performed by MDB. These MDB all use a @RunAs(SYSTEM)
annotation to mark them as system elements.
One of these MDB has to run some code which is protecetd through @RolesAllowed(WORKSPACE)
, which the SYSTEM
role doesn't have, obviously, but which the user
(a human being, mind you) that started the process has.
So, my question is quite simple : is there any way (through asynchronous invocation, as an example) to have my MDB to change its principal to be my user
instead of SYSTEM
?
Like Mike Braun answer suggest, this is not possible according to JavaEE specifications.
And that is unfortunate. But, what is a little less unfortunate is that there is some code to do that kind of things (application-server specific), hidden in that application server implementation of @RunAs
. In Glassfish, that particular code is in the com.sun.enterprise.security.auth.login.LoginContextDriver
class, and particularly in its LoginContextDriver#loginPrincipal
method.
So, to have one part of code using a specific principal, I defined an interface
public interface Sudoer {
public <Result> Result sudo(String user, SudoOperation<Result> operation);
}
which I implemented for Glassfish as so :
public class GlassfishSudoer implements Sudoer {
@Override
public <Result> Result sudo(String user, SudoOperation<Result> operation) {
try {
LoginContextDriver.loginPrincipal(user, "autocat");
return operation.perform();
} catch (Exception e) {
throw new UnableToSudoException(e);
} finally {
LoginContextDriver.logout();
}
}
}
And when using it, the part which wants to have some code "sudoed" only has to provide an implementation of the SudoOperation, like
component.sudo(userLogin, new SudoOperation<Void>() {
public Void perform() {
/* do some sudoed code */
return null;
}
});
Advantage of this method is that, provided the given application server has some code to handle @RunAs
, you can use that code to implement your own sudoer (I'm thinking about extracting that into a sudo-ejb library ...).