In EJB, a caller's identity is derived through the principal and credential properties of the initial context used to do the initial JNDI lookup of the bean.
On the other hand:
In order to avoid the overhead of both JNDI lookups as well as bean creation, the dominant best practice design pattern - advocated by nearly every EJB design reference, is to cache remote/local interface references and/or use the service locator pattern.
The side effect of this is that every user in the calling system (for example a web tier), despite having different business roles, has the same identity in the eyes of the EJB container! As a result, container managed security as well as role-based permissions have absolutely no value!
Given the design decision to cache remote/local interface references, what then is the best practice for passing a caller's identity to the EJB container?
A very unattractive solution is to pass a custom identity object as a parameter to every bean method, and to settle for the programmatic rather than declarative security features of the container.
What solutions have others implemented? Please give feedback!
First, I do not believe a caller's identity is derived from the principal and credential properties of the intial context used to perfrom jndi lookups to the home. When I first started working with EJB, I thought so, too. But there are typically many other ways to authenticate with the server the context comes from. Many times via normal web authentication, many times via JAAS login modules. Also, there could be mutual auth between servers of different vendors, based on certs, and probably another dozen or so specific auth mechanisms.
In other words, the initial context constructor properties is a way to perform authentication with the container, but not the only way.
IF the web app has a configured security constraint, then auth must have been performed, and that context is propigated on calls to the ejb tier (assuming it has security constraints).
For example, a servlet could hold a reference to a local or remote ejb object that it creates on init. The servlet is then requiring authentication. When the servlet is invoked, it calls a method on the ejb, the principal will delegate down to the ejb.
A Bean realizes it's caller on a business method basis, by consulting the context.getCallerPrincipal method, saving a local reference to that value for future calls is a mistake. The same bean can serve in its life multiple clients with differing principals.
If you do not have authentication for a particular page, it is not guaranteed that the principal is going to be available to the web app, and thus, the ejb. This behavior I have observed behave differently on different web containers.
Hope this helps clear things up.
The other problem with that type of security provided via JNDI is that when the principal isn't allowed to do something, it throws an exception. That is lame. Exceptions are for unexpected conditions, not normal flows within the program. I don't use it at all, rather using a custom security.
If you think about it, that makes sense, because your UI shouldn't necessarily be tied to your EJBs or EJB calls. Sometimes, a UI function involves several EJB calls, and you can create unnecessary coupling when you tie them all together....