I've been trying to dig through the JBoss source to understand how the caller 
principal is set for the home.create() call, and I think it's possible that 
there is a bug in the JBoss code.  It's definitely possiblet hat Im wrong and I 
am just not understanding something correctly, but let me show you what I 
looked at.

In org.jboss.ejb.plugins.SecurityInterceptor#setContainer, if the 
runAsCallerIdentity() == true, which is default, the runAsIdentity is never 
initialized and remains null.

        
  |        public void setContainer(Container container)
  |        {
  |           super.setContainer(container);
  |           if (container != null)
  |           {
  |              BeanMetaData beanMetaData = container.getBeanMetaData();
  |              ApplicationMetaData applicationMetaData = 
beanMetaData.getApplicationMetaData();
  |              AssemblyDescriptorMetaData assemblyDescriptor = 
applicationMetaData.getAssemblyDescriptor();
  |              securityRoles = assemblyDescriptor.getSecurityRoles();
  |     
  |              SecurityIdentityMetaData secMetaData = 
beanMetaData.getSecurityIdentityMetaData();
  |              if (secMetaData != null && secMetaData.getUseCallerIdentity() 
== false)
  |              {
  |                 String roleName = secMetaData.getRunAsRoleName();
  |                 String principalName = secMetaData.getRunAsPrincipalName();
  |     
  |                 // the run-as principal might have extra roles mapped in 
the assembly-descriptor
  |                 Set extraRoleNames = 
assemblyDescriptor.getSecurityRoleNamesByPrincipal(principalName);
  |                 runAsIdentity = new RunAsIdentity(roleName, principalName, 
extraRoleNames);
  |              }
  |     
  |              securityManager = container.getSecurityManager();
  |              realmMapping = container.getRealmMapping();
  |     
  |              try
  |              {
  |                 // Get the timeout method
  |                 ejbTimeout = TimedObject.class.getMethod("ejbTimeout", new 
Class[]{Timer.class});
  |              }
  |              catch (NoSuchMethodException ignore)
  |              {
  |              }
  |           }
  |    }
   
Later on, in when an EJB looks up another EJB, the 
org.jboss.ejb.plugins.SecurityInterceptor#invokeHome is called.  There is a 
call that indiscrimintately pushes the runAsIdentity onto the stack.  Since 
this is null from before, the next call is run with a null caller identity.  
This is confirmed by the TRACE below.


  |    public Object invokeHome(Invocation mi) throws Exception
  |    {
  |       // Authenticate the subject and apply any declarative security checks
  |       checkSecurityAssociation(mi);
  | 
  |       /* If a run-as role was specified, push it so that any calls made
  |        by this bean will have the runAsRole available for declarative
  |        security checks.
  |       */
  |       SecurityActions.pushRunAsIdentity(runAsIdentity);
  | 
  |       try
  |       {
  |          Object returnValue = getNext().invokeHome(mi);
  |          return returnValue;
  |       }
  |       finally
  |       {
  |          SecurityActions.popRunAsIdentity();
  |          SecurityActions.popSubjectContext();
  |       }
  |    }
  | 

Here is the trace where you can see the caller identity of null being pushed, 
and the subsequent exception that is caused by it.


  | 2005-11-20 08:14:53,140 TRACE 
[org.jboss.security.plugins.JaasSecurityManager.mwo] doesUserHaveRole(Set), 
subject: Subject:
  |     Principal: admin
  |     Principal: Roles(members:Guest,Administrator)
  | 
  | 2005-11-20 08:14:53,140 TRACE 
[org.jboss.security.plugins.JaasSecurityManager.mwo] 
roles=Roles(members:Guest,Administrator)
  | 2005-11-20 08:14:53,140 TRACE 
[org.jboss.security.plugins.JaasSecurityManager.mwo] hasRole(Administrator)=true
  | 2005-11-20 08:14:53,140 TRACE 
[org.jboss.security.plugins.JaasSecurityManager.mwo] hasRole=true
  | 2005-11-20 08:14:53,140 TRACE [org.jboss.security.SecurityAssociation] 
pushRunAsIdentity, runAs=null
  | 2005-11-20 08:14:53,140 DEBUG [com.myejb.jboss.Session2SecurityProxy] 
Entered setEJBContext(EJBContext)
  | 2005-11-20 08:14:53,156 TRACE 
[org.jboss.security.plugins.JaasSecurityManager.mwo] getPrincipal, cache info: 
null
  | 2005-11-20 08:14:53,156 TRACE [org.jboss.security.SecurityAssociation] 
popRunAsIdentity, runAs=null
  | 2005-11-20 08:14:53,156 TRACE [org.jboss.security.SecurityAssociation] 
popSubjectContext, [EMAIL PROTECTED],subject=7683106}
  | 2005-11-20 08:14:53,156 ERROR [org.jboss.ejb.plugins.LogInterceptor] 
TransactionRolledbackException in method: public abstract 
com.myejb.Session1Remote com.myejb.Session1Home.create() throws 
javax.ejb.CreateException,java.rmi.RemoteException, causedBy:
  | java.lang.IllegalStateException: No valid security context for the caller 
identity
  | 

It seems the StatelessSessionInstanceInterceptor is responsible for pushing the 
caller identity into the StatelessSessionEnterpriseContext, but it is pulling 
it from the methodInvocation.  I tried to trace this all the way back to where 
the MethodInvocation was formed by looking at the proxy compiler, but I don't 
think I understand it well enough.  To me it didn't look like the principal is 
set on the MI by the proxy itself, but I could be wrong.

When the code finally gets to the point where it calls getCallerPrincipal(), 
here is the code that gets executed.  I've watched this in the debugger.  The 
beanPrincipal is null, principal is null, and rm is not null, so it tries to 
set the beanPrincipal by calling peekRunAsIdentity.  As previously established, 
this is null so I get the "No valid security context" error.


  |       Principal getCallerPrincipalInternal()
  |       {
  |          if (beanPrincipal == null)
  |          {
  |             RealmMapping rm = con.getRealmMapping();
  |             if (principal != null)
  |             {
  |                if (rm != null)
  |                   beanPrincipal = rm.getPrincipal(principal);
  |                else
  |                   beanPrincipal = principal;
  |             }
  |             else if (rm != null)
  |             {
  |                // Check for the caller's run-as identity, not this bean's 
run-as
  |                beanPrincipal = SecurityActions.peekRunAsIdentity(1);
  |                if (beanPrincipal == null)
  |                {
  |                   // Let the RealmMapping map the null principal
  |                   beanPrincipal = rm.getPrincipal(principal);
  |                }
  |             }
  |             else
  |             {  // Check for a unauthenticated principal value
  |                ApplicationMetaData appMetaData = 
con.getBeanMetaData().getApplicationMetaData();
  |                String name = appMetaData.getUnauthenticatedPrincipal();
  |                if (name != null)
  |                   beanPrincipal = new SimplePrincipal(name);
  |             }
  |          }
  |          if( beanPrincipal == null )
  |          {
  |             throw new IllegalStateException("No valid security context for 
the caller identity");
  |          }
  |          return beanPrincipal;
  |       }
  | 

Is it possible that the invokeHome method in SecurityInterceptor should be 
doing a conditional check on the pushRunAsIdentity?  It seems that it should 
not be pushing it if the intent is to run as the caller identity.

Thanks,
Matt

View the original post : 
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3908070#3908070

Reply to the post : 
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3908070


-------------------------------------------------------
This SF.Net email is sponsored by the JBoss Inc.  Get Certified Today
Register for a JBoss Training Course.  Free Certification Exam
for All Training Attendees Through End of 2005. For more info visit:
http://ads.osdn.com/?ad_id=7628&alloc_id=16845&op=click
_______________________________________________
JBoss-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jboss-user

Reply via email to