Problem when invoking Local EJB from new thread
doychin Nov 1, 2011 4:57 AMDuring my migration to JBoss AS 5/6 I found this problem and it lies within a new PreSecurity interceptor plus the change that SecurityContext is now shared between all threads.
So I changed my startup configuration to include -Dorg.jboss.security.context.ThreadLocal=true
and also made changes from https://issues.jboss.org/browse/JBAS-7037
Here is the end result:
private Object process(Invocation mi, boolean isInvoke) throws Exception
{
//No Security in the absence of SecurityDomain
if(securityDomain == null)
{
if(isInvoke)
return getNext().invoke(mi);
else
return getNext().invokeHome(mi);
}
if(log.isTraceEnabled()) {
log.trace("process:isInvoke=" + isInvoke + " bean=" + container.getServiceName());
}
SecurityIdentity si = null;
String incomingDomain = null;
Method m = mi.getMethod();
boolean isEjbTimeOutMethod = m != null && m.getName().equals(timedObjectMethod);
//For local ejb invocations
if(mi.isLocal() && !isEjbTimeOutMethod) {
if(log.isTraceEnabled()) {
log.trace("True mi.isLocal() && !isEjbTimeOutMethod");
}
//Cache the security context
SecurityContext sc = SecurityActions.getSecurityContext();
if(sc == null) {
if(log.isTraceEnabled()) {
log.trace("sc is null");
log.trace("creating security context for domain " + securityDomain);
}
sc = SecurityActions.createAndSetSecurityContext(securityDomain,
container.getSecurityContextClassName());
} else {
incomingDomain = sc.getSecurityDomain();
if(log.isTraceEnabled()) {
log.trace("incoming domain is " + incomingDomain);
log.trace("sc id " + Integer.toHexString(sc.hashCode()));
}
}
si = SecurityActions.getSecurityIdentity(sc);
SecurityActions.setSecurityManagement(sc, container.getSecurityManagement());
// set the container's security domain in the security context
SecurityActions.setSecurityDomain(sc, this.securityDomain);
if(log.isTraceEnabled()) {
log.trace("setting security domain to " + securityDomain);
log.trace("SecurityIdentity=" + SecurityActions.trace(si));
}
//Set the security context on the invocation
mi.setSecurityContext(sc);
}
else
{
if(log.isTraceEnabled()) {
log.trace("False mi.isLocal() && !isEjbTimeOutMethod");
}
establishSecurityContext(mi);
}
try
{
//Establish the run-as on the SC as the caller SC
SecurityContext currentSC = SecurityActions.getSecurityContext();
SecurityActions.pushCallerRunAsIdentity(currentSC.getOutgoingRunAs());
log.trace("Going to the SecurityInterceptor with SC="+SecurityActions.trace(currentSC));
if(isInvoke)
return getNext().invoke(mi);
else
return getNext().invokeHome(mi);
}
finally
{
SecurityActions.popCallerRunAsIdentity();
if(mi.isLocal()) {
if(si != null)
SecurityActions.setSecurityIdentity(SecurityActions.getSecurityContext(), si);
if(incomingDomain != null) {
SecurityActions.setSecurityDomain(SecurityActions.getSecurityContext(),
incomingDomain);
if(log.isTraceEnabled()) {
log.trace("restoring incoming domain to " + incomingDomain);
}
}
}
if(log.isTraceEnabled()) {
log.trace("Exit process():isInvoke=" + isInvoke);
}
}
}
As you can see now in case getSecurityContext returns null for sc code creates new security context for the domain. This happens when new thread created by ServletListener tries to execute Local EJB. In the original code there was only check for sc != null and then null sc is pased which generates NPE.
This error is present in both JBoss 5 and 6.
I hope this will help other people with similar problems.