8 Replies Latest reply on Aug 26, 2008 9:25 AM by kimbaltrue

    Unable to get Subject from SecurityAssociation when calling

    kimbaltrue

      I'm using JBOSS-4.2.3.GA under Jdk 1.6_05

      I have an EJB3.0 Webservice Bean that calls two other EJB3.0 beans to do it's work. Inside the Webservice Bean I can call SecurityAssociation.getSubject and get the current security context subject. However, in the utility beans when I call SecurityAssociation.getSubject I only get a null.

      I have tried adding <login-module code="org.jboss.security.ClientLoginModule" flag="required" />
      to my login domain as suggested in the FAQ. I'm currently using the UserRolesLoginModule and security in general seems to work fine. The Caller Principal is propigated so all the regular stuff works. It's just SecurityAssociation that seems empty when crossing the EJB boundary.

      The EJB are both in the same EAR, but in different JAR files, and I'm using the local interface reference from JNDI to call the beans.

        • 1. Re: Unable to get Subject from SecurityAssociation when call
          ragavgomatam

          Shouldn't you be using

          ejbContext.getCallerPrincipal()
          from within ejb's ?

          • 2. Re: Unable to get Subject from SecurityAssociation when call
            kimbaltrue

            Yes, I am using getCallerPrincipal to get the caller principal, but I need the caller's Subject as well. That's not available in the standard EJB API set, but I need it to get the roll list.

            • 3. Re: Unable to get Subject from SecurityAssociation when call
              ragavgomatam

              I don't think you can get the entire role list. What you can do is to test if the Principal has a given role by using :-

              ejbContext.isCallerInRole()




              • 4. Re: Unable to get Subject from SecurityAssociation when call
                kimbaltrue

                When the initial EJB bean is called - it's a EJB 3.0 webservice bean - I'm able to get the current context Subject, and from that I can get the principal sets, and from them I can get the full list of a user's roles.

                That's actually working.

                The problem occurs when I call another EJB 3.0 bean from the first bean. The second bean seems to have lost the initial security context so that I can't get the context Subject.

                As for the isCallerInRole this is only useful when you already know the the role. That's taken care of by the @RolesAllowed annotation so I really don't need to call isCallerInRole. What I'm trying to do is allow for dynamic role based access to specific data elements in the database, and I can only do that if I can pull the user's role list.

                Also, I'm concerned that if the Subject context is lost then I might not be able to call from one Application server instance to another using the same security associations.

                • 5. Re: Unable to get Subject from SecurityAssociation when call
                  ragavgomatam

                  Hi,

                  Got it...Can you please post the code as to how these 2 ejb's are calling each other ? That could perhaps give us clues.

                  • 6. Re: Unable to get Subject from SecurityAssociation when call
                    kimbaltrue

                    The first bean is a standard EJB3.0 webservice bean.

                    @WebService(name = "Reference", serviceName = "Reference", targetNamespace = "http://legion.ccf.org")
                    @SOAPBinding(style = SOAPBinding.Style.DOCUMENT)
                    /*
                     * JBOSS specific security annotations
                     */
                    @SecurityDomain("tactus-domain")
                    @WebContext(authMethod = "BASIC", contextRoot = "/Legion/Ref", transportGuarantee = "NONE", secureWSDLAccess = false)
                    
                    
                    
                    @Stateless(name = "Reference")
                    @Remote(Reference.class)
                    @Local(Reference.class)
                    @TransactionManagement(TransactionManagementType.BEAN)
                    @Interceptors(TrackingMetrics.class)
                    public class ReferenceWebBean implements ReferenceWeb
                    {
                     protected AdapterRegistry registry = null;
                     protected ReferenceWeb adapter = null;
                    
                    
                     /* (non-Javadoc)
                     * @see org.ccf.legion.ReferenceWeb#getUserRoles()
                     */
                     @Override
                     public List<String> getUserRoles()
                     {
                     return adapter.getUserRoles();
                     }
                    }
                    


                    The adapter object is a simple POJO used to do work. It uses the following code to find the second bean using the JNDI string "Legion/ReferenceBean/local".

                    The ReferenceWebBean (EJB3.0 #1) is a web service bean and calls other beans to do it's work. The ReferenceBean (EJB3.0 #2) is a stateless EJB bean which accesses the database.


                    private Object findJNDIResource(String mappedName)
                    {
                     Object result = null;
                    
                     try
                     {
                     InitialContext context = new InitialContext();
                     result = context.lookup(mappedName);
                     }
                     catch (NamingException e)
                     {
                     log.debug(messages.getString("AdapterRegistry.24", mappedName));
                     // if not found just return null
                     }
                    
                     return result;
                    }
                    


                    After getting the local inteface to the ReferenceBean (EJB3.0 #2) the adapter calls a method on that bean which then does the following:



                     public List<String> getRoles()
                     {
                     List<String> rolelist = new java.util.ArrayList<String>();
                    
                     Subject subject = org.jboss.security.SecurityAssociation.getSubject();
                     if(subject == null)
                     {
                     log.debug("Subject is null");
                     return rolelist;
                     }
                    
                     Set<SimpleGroup> groups = subject.getPrincipals(SimpleGroup.class);
                     if(groups.isEmpty())
                     log.debug("No Simple Groups");
                     else
                     {
                     for(SimpleGroup group : groups)
                     {
                     if(group.getName().compareToIgnoreCase("Roles")==0)
                     {
                     java.util.Enumeration<?> en = group.members();
                     while(en.hasMoreElements())
                     {
                     Object obj = en.nextElement();
                     if(obj instanceof Principal)
                     {
                     String name = ((Principal)obj).getName();
                     rolelist.add(name);
                     log.debug("Role name = "+name);
                    
                     }
                     else
                     {
                     log.debug("Simple Group Content: " + obj.getClass().getName());
                     }
                     }
                     }
                     }
                     }
                    
                     return rolelist;
                     }
                    
                    


                    If I put the above code directly in the webservice bean (ReferenceWebBean or EJB3.0 #1) it works, and returns the roles list. If I put this code in the second EJB3.0 bean (ReferenceBean EJB3.0 #2) where the database connections are then it returns a null for the Subject.

                    These two beans are in the same EAR file, but different JAR files.


                    The second EJB3.0 bean (ReferenceBean EJB3.0 #2) looks like this:

                    @Stateless(name = "ReferenceBean") //$NON-NLS-1$
                    @Remote(Reference.class)
                    @Local(Reference.class)
                    @TransactionManagement(TransactionManagementType.BEAN)
                    @Interceptors(TrackingMetrics.class)
                    public class ReferenceBean extends LegionServiceSupport implements Reference
                    {
                     private static final Log log = LogFactory.getLog(ReferenceBean.class);
                     private static final Messages messages = Messages
                     .getMessages(ReferenceBean.class);
                    
                    
                     @PersistenceContext(unitName = "LegionModel") //$NON-NLS-1$
                     private EntityManager manager = null;
                    
                    
                    
                    
                    


                    I hope that helps explain what's going on. The codes a bit more involved than what I've shown, but these are the relevant parts.


                    • 7. Re: Unable to get Subject from SecurityAssociation when call
                      ragavgomatam

                       

                      If I put the above code directly in the webservice bean (ReferenceWebBean or EJB3.0 #1) it works, and returns the roles list.

                      I think this explains it. Can Ejb #1 ReferenceWebBean , have a reference to ReferenceBean and have it annotated @Ejb ? This would make the container inject the ReferenceBean into ReferenceWebBean . Then try to see if you get the Roles inside ReferenceBean . What i suspect is that , when the PoJo calls ReferenceBean , the Subject is lost , in other words not propagated through. Can you have a ReferenceBean reference inside
                      ReferenceWebBean with @Ejb annotation ?

                      • 8. Re: Unable to get Subject from SecurityAssociation when call
                        kimbaltrue

                        So, it's not propigating subject between EJB's if they're called through the interface returned from JNDI, but it is propogating it with injection? I would have thought that the injection reference would have come from JNDI to begin with. Does JBOSS have a parallel reference mechanism with JNDI so that the JNDI reference is different from an injected reference?

                        It may take some time for me to try this, but if it does work I probably can't depend on it for a long term solution. The code is layered with pluggable components so it's not going to take well to having one EJB hard bound to another through an annotation reference.

                        Is there some way to enforce subject propigation using an JNDI reference using something like Subect.doAs?