I've attached patches for geronimo/openejb2 trunk to GERONIMO-2313
that fix this problem, but I'd prefer to get some review before I
apply them.
thanks
david jencks
On Aug 10, 2006, at 2:47 PM, David Jencks wrote:
A user noticed that when their web app called an ejb, despite the
authentication of the user in the web app, in the ejb
isCallerinRole always returns false. I've been investigating this
and think we have some problems in how we handle run-as identities
and the ContextManager currentCaller and nextCaller values. I'm
also not sure where our defaultSubject idea fits into this. I'll
try to summarize my understanding of the specs and what we should
be doing, and make a bit of a proposal.
I'd really appreciate some review of how I think its supposed to
work and comments on my proposal. I'm working on a patch to
implement the proposal, but I believe we have to do something since
what we do now appears to be broken.
web apps (2.4 spec):
SRV.12.3 states that the getRemoteUser, isUserInRole, and
getUserPrincipal methods should return null, false, and null if
there is no authenticated user. Following the specs' usual policy
of not discussing cross context dispatch, we are left to guess that
even if a run-as role is specified somewhere the target of a cross-
context dispatch should continue to return null, false, null with
no actual authenticated user.
SRV.12.7 states that if a run-as element is specified, all calls
from any servlet in the application to an ejb must be done under a
subject associated with the run-as role.
The spec does not seem to account for the possiblity that calls to
ejbs could be done either pre- or post- user authentication: if a
run-as role is specified, all calls will be made using it whether
or not the user is authenticated.
We've introduced the concept of a defaultSubject that is used if
the user is not authenticated, but will not interfere with using
the users actual identity when the user is authenticated. IIUC (I
haven't tested) currently the default subject is used in a way that
interferes with the "null, false, null" requirements for
getRemoteUser, isUserInrole, and getUserPrincipal.
ejbs: (2.1 spec)
21.3.4.1 indicates that the run-as identity specified for an ejb
does not affect any security decisions for the ejb itself, but only
specifies the identity to be used when it is calling other ejbs ( I
need to check which identity is used use with resource adapters
using container managed security). Methods such as isCallerInRole
use the caller's identity, not the run-as identity (21.2.5.1)
----------------
We're keeping track of these two identities in ContextManager
currentCaller and nextCaller (threadLocals). All security
decisions are based on the currentCaller value. When a run-as
value is specified for an ejb, it's put into the nextCaller. When
an ejb is called, the nextCaller value is shifted into the
currentCaller: this is supposed to occur before the run-as is put
into the nextCaller.
My understanding of the requirements is that we should be:
- when a web user is authenticated we should put the subject into
currentCaller and nextCaller. The currentCaller value will be used
for security decisions in the web app, and the nextCaller value for
security decisions on any ejbs it calls.
- when a run-as role is specified for a web app we put the subject
associated with the run-as role into nextCaller (whether or not the
current user is authenticated)
- cross context dispatch may replace the nextCaller if run-as is
specified for the target, and the previous nextCaller value needs
to be restored on return. This can never affect currentCaller.
- defaultSubject (a non-spec concept) should be put into both
currentCaller and nextCaller unless run-as is specifed in which
case run-as goes in the nextCaller.
----------------
Currently the web security stuff is pretty much ignoring nextCaller
which is causing the authenticated user to be lost in ejb calls:
this causes the problem the user reported. I'm mystified as to how
the tck passes.
----------------
I think that perhaps we should organize this information into one
object with more explicit operations on the ContextManager:
class Callers {
Subject currentCaller;
Subject nextCaller;
}
in ContextManager:
void setCallers(Subject currentCaller, Subject nextCaller)
//called for servlet cross context dispatch to set the target app
run-as identity
Callers setNextCaller(Subject nextCaller);
//called for ejb call to shift the next caller to current caller
and set the next caller to the run-as subject.
// We need either another method with no params for the "no run-as"
case or if null is suppled the nextCaller is not changed
Callers pushNextCaller(Subject nextCaller);
//called on return from an ejb call or servlet-cross-context-dispatch.
void popCallers(Callers oldCallers);
This would reduce the number of thread locals in ContextManager by
at least one.
Thanks
david jencks