3 Replies Latest reply on Sep 9, 2013 9:42 PM by Brian Wallis

    MDB and current principal

    Brian Wallis Master

      I've been searching and reading on this topic and don't seem to be able to get it to work, what I have below is what I have read about and it is AFAIK the correct way to do this.

       

      I'm running this code in JBoss EAP 6.1.0.GA. The two beans are packaged in the same ejb jar file which is itself in an ear file.

       

      I have an MDB like so (this is cut down a bit)

       

      @MessageDriven(name = "TaskListHumanTaskRequiredReceiver",
             activationConfig = { @ActivationConfigProperty( propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
                         @ActivationConfigProperty( propertyName = "destination", propertyValue = "topic/TaskIn"), })
      @SecurityDomain(harvey-security-domain)
      @RunAsPrincipal("harvey")
      @RunAs("Admin")
      @PermitAll
      public class HumanTaskRequiredReceiver implements MessageListener
      {
          private static final Logger LOGGER = LoggerFactory.getLogger(HumanTaskRequiredReceiver.class);
      
      
          @Resource
          MessageDrivenContext sessionContext;
         
          @EJB
          private TaskServiceBeanLocal taskServiceBean;
      
      
          public void onMessage(Message message)
          {
              LOGGER.info("Caller Principal is " + sessionContext.getCallerPrincipal());
              LOGGER.info("Has roll Admin? " + sessionContext.isCallerInRole("Admin"));
              Task task = new Task();
      // ...
              taskServiceBean.save(task);
          }
      }
      

       

      and I have my stateless session bean like so

       

      @Stateless
      public class TaskServiceBean implements TaskServiceBeanLocal, TaskServiceBeanRemote
      {
          private static final Logger LOGGER = LoggerFactory.getLogger(TaskServiceBean.class);
                 
          @Resource
          SessionContext sessionContext;
      
      
          public Task save(Task task)
          {
              LOGGER.info("Caller Principal is " + sessionContext.getCallerPrincipal());
              LOGGER.info("Has roll Admin? " + sessionContext.isCallerInRole("Admin"));
      // ...
          }
      }
      

       

      I don't have any additional deployment descriptors, the annotations should do all that I need. But it is not working.

       

      The output from the logging is always

      Caller Principal is anonymous

      and

      Has roll Admin? false

       

      I am trying to get the caller principal in the called session bean to be "harvey" and the role "Admin" when it is called from the MDB. Is there something missing from my setup?

       

      The security domain is configured in standalone.xml like so

       

      <security-domain name="harvey-security-domain" cache-type="default">
          <authentication>
        <login-module code="LdapExtended" flag="optional">
           <module-option name="java.naming.provider.url" value="ldap://10.64.33.105:389"/>
           <module-option name="bindDN" value="cn=Administrator,CN=Users,DC=melb-dev,DC=oopl,DC=com,DC=au"/>
           <module-option name="bindCredential" value="Object123"/>
           <module-option name="baseCtxDN" value="CN=Users,DC=melb-dev,DC=oopl,DC=com,DC=au"/>
           <module-option name="baseFilter" value="(sn={0})"/>
           <module-option name="rolesCtxDN" value="CN=Users,DC=melb-dev,DC=oopl,DC=com,DC=au"/>
           <module-option name="roleFilter" value="(member={1})"/>
           <module-option name="roleNameAttributeID" value="cn"/>
           <module-option name="roleAttributeIsDN" value="false"/>
           <module-option name="roleRecursion" value="0"/>
           <module-option name="searchScope" value="ONELEVEL_SCOPE"/>
           <module-option name="allowEmptyPasswords" value="false"/>
        </login-module>
        <login-module code="RealmDirect" flag="optional">
           <module-option name="password-stacking" value="useFirstPass"/>
        </login-module>
          </authentication>
      </security-domain>
      

       

      and the application realm has a user named "harvey" with the role "Admin" (the ldap doesn't).

       

      thanks,

        • 1. Re: MDB and current principal
          Brian Wallis Master

          Tried explicitly doing a JAAS login but I'm obviously missing something here.

           

              public void onMessage(final Message message)
              {
                  try
                  {
                      LoginContext lc = new LoginContext("harvey-security-domain", new CallbackHandler()
                      {
          
                          @Override
                          public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
                          {
                              for (int i = 0; i < callbacks.length; i++)
                              {
                                  if (callbacks[i] instanceof NameCallback)
                                  {
                                      ((NameCallback) callbacks[i]).setName("harvey");
                                  }
                                  else if (callbacks[i] instanceof PasswordCallback)
                                  {
                                      ((PasswordCallback) callbacks[i]).setPassword("xxx".toCharArray());
                                  }
                                  else
                                  {
                                      throw new UnsupportedCallbackException(
                                              callbacks[i], "Callback class not supported");
                                  }
                              }
                          }
                      });
                      LOGGER.info("Login using harvey userID");
                      lc.login();
                      LOGGER.info("Logged in subject is "+lc.getSubject());
                      Subject.doAs(lc.getSubject(), new PrivilegedAction<Object>()
                      {
                          public Object run()
                          {
                              Subject.getSubject(AccessController.getContext());
                              InitialContext ic;
                              try
                              {
                                  ic = new InitialContext();
                                  EJBContext sctxLookup = (EJBContext) ic.lookup("java:comp/EJBContext");
                                  Principal principal = sctxLookup.getCallerPrincipal();
                                  LOGGER.info("local Principal is " + principal);
                             }
                             catch(Exception e)
                             {
                                 // ...
                             }
                         }
                     }
                }
            }
          
          

           

          I get logging output like this:

           

          17:20:03,942 INFO  Login using harvey userID

          17:20:03,949 INFO  Logged in subject is Subject:

            Principal: harvey

            Principal: Roles(members:Nurse,CPF,Admin,infomedix)

            Principal: CallerPrincipal(members:harvey)

          17:20:03,950 INFO  local Principal is anonymous

           

          So, obviously the ejb context is not updated when running within the doAs. I get the same result if I call into another session bean from within the doAs, still an anonymous principal so it isn't updated for the called bean either.

           

          So, what am I not getting here? (I have seen this post that describes exactly what I'm seeing, Re: Call from MDB to SSB is always anonymous but it didn't really help me work out what I'm doing wrong)

           

          thanks.

          • 2. Re: MDB and current principal
            Brian Wallis Master

            I've got this working now with the Subject.doAs() call in the onMessage() MDB method. I was missing the ClientLoginModule in my login modules configuration.

             

            This is still very clumsy though. I don't think I should need all that extra code and hard coded username/password values in the MDB.

             

            The use of the @SecurityDomain, @RunAs and @RunAsPrincipal annotations in the MDB don't seem to have any effect at all.

             

            Again, I must be missing something here, any idea what?

             

            thanks

            1 of 1 people found this helpful
            • 3. Re: MDB and current principal
              Brian Wallis Master

              To continue with answering my own questions.

               

              If the MDB is calling a session bean that doesn't have any security annotations or descriptors then the session bean is not secured and the role or principal does not seem to be available from its context so SessionContext.getCallerPrincipal() always returns a single entry, anonymous.

               

              Add a @PermitAll to the top of the session bean and suddenly calls to SessionContext.getCallerPrincipal() start returning what I expected, ie: what I configured in the @RunAs and the @RunAsPrincipal annotations.

               

              So in summary, to have a role and principal available in calls to session beans from an MDB, the session beans have to have some security setup.