Imagine a requirement for programmatic security from within a MDB. The message has the username and the application needs to call other EJBs with that user as the principal. The security model in EJB is too simplistic to avoid programmatic security. And the JMS message acts as a trigger to automatically initiate business logic on a user's behalf. Large classes of enterprise applications probably fall within that description.
Mastering Enterprise JavaBeans Second Edition (Roman, Ambler & Jewell):
Ch.9 Pg 267
"Since message-driven beans receive JMS messages rather than RMI-IIOP calls, they do not receive any credentials when they are called. It is therefore illegal for message-driven beans to perform any programmatic or declarative security. As far as propagation, it is also illegal for message-driven beans to propagate the nonexistent client's credentials."
This doesn't look promising!
One possible approach is within onMessage to put the username inside the message and then within onMessage login as that user using JAAS and a login module that doesn't require the password from within the container. Admittedly this introduces a weakness within the security but providing that access to the message queue is tightly controlled then it isn't so bad.
However, the specification appears unclear (at least to me) as to whether this is possible or permissable. Here is what the specification says about such things.
Enterprise JavaBeans Specification Version 2.0 Final Release (Sun Microsystems):
15.4.3 The MessageDrivenContext interface
"The getCallerPrincipal method is inherited from the EJBContext interface. Message driven bean instances must not call this method."
"The isCallerInRole method is inherited from the EJBContext interface. Message-driven bean instances must not call this method."
15.5.1 Operations allowed in the methods of a message-driven bean class
"Invoking the getCallerPrincipal and isCallerInRole methods is disallowed in the message-driven bean methods because the Container does not have a client security context. The Container must throw and log the java.lang.IllegalStateException if either of these methods is invoked."
So you can't getCallerPrincipal within a message driven bean which doesn't seem too promising. But doesn't logging in using JAAS effectively sets the caller principal. Well not exactly...
184.108.40.206 Application Client Authentication
"After [JAAS] authentication is completed, a credential is associated with the client’s thread of execution, which is used for all invocations on enterprise beans made from that thread."
If the credential is associated with the client's thread which in this case is the thread that is controlling the MDB then can it be relied upon? The thread controlling the MDB is under the control of the container that pools and reuses these threads and that presumably could cause problems for authentication that is attached to the thread.
JBoss seems to work fine here. A message is received with a username. The onMessage uses JAAS to login the user. The authentication is attached to the thread. And then subsequently other EJBs are called. These EJBs use getCallerPrincipal and receive the username on which programmatic security logic works.
But is it safe to rely upon JAAS within a message driven bean across all application servers? It is quite possible that I am unduly worrying about this and that all application servers will always honour the authentication that it receives through the message driven bean thread. I have not seen anything to indicate that this is the case and seek clarification.
Maybe programmatic security in message driven beans may make a good chapter in a book or perhaps the specification may be amended to clarify what seems to be quite an obvious requirement. Until then I'm left with what may be a dubious hack in a message driven bean to get programmatic security.