8 Replies Latest reply on Feb 21, 2014 4:14 AM by emmartins

    Trouble getting principal name in EJB

    tbronzan

      I'm having problems with the session context inside an EJB not being able to find the principal name under certain circumstances.

       

      Here's my EJB

       

      @Stateless
      @SecurityDomain("MyDomain")
      public class UserCookieEJB implements IUserCookieRetrieverLocal,
        IUserCookieRetrieverRemote, IUserCookieUpdaterLocal, IUserCookieUpdaterRemote
      {
        @Resource
        private SessionContext context;
      
        protected String getPrincipalName()  //helper method used in interface public methods
        {
             return context.getCallerPrincipal().getName();
        }
        ...
      }
      
      
      

       

       

      I have two web projects and a common project that they both use classes from, all of which are packaged in an ear.  If I do a lookup for the UserCookieEJB using a class from one of the web projects then the call to getPrincipalName() returns the correct principal.  However, if the UserCookieEJB is looked up from one of the classes in the common project, getPrincpalName() returns anonymous.  The ejb subsystem has <default-security-domain value="MyDomain"/> set.  The classes in the web projects and common project use a helper class to do the lookup, so they lookups are done the same way and the helper class is located in the common project.

       

      EDIT:  It would seem that there is a problem with the SessionContext in general as I'm seeing this in another place in the application as well.  Sometimes the SessionContext has the right principal, other times it does not.

       

      EDIT 2: Ok it looks like it's a problem with the principal not being propagated properly, and may be similar to this: Principal propagation from web to ejb

       

      Here is the output I get when I check the principal name in the two EJBs we have the use the @Resource SessionContext.  It looks like it only gets the correct principal name from one thread.

       

      16:18:02,378 ERROR [stderr] (default task-4) SessionInfoEJB: superuser
      16:18:02,410 ERROR [stderr] (default task-4) SessionInfoEJB: superuser
      16:18:02,440 ERROR [stderr] (default task-4) SessionInfoEJB: superuser
      16:18:02,477 ERROR [stderr] (default task-4) SessionInfoEJB: superuser
      16:18:02,499 ERROR [stderr] (default task-4) SessionInfoEJB: superuser
      16:18:02,520 ERROR [stderr] (default task-4) SessionInfoEJB: superuser
      16:18:02,538 ERROR [stderr] (default task-4) UserCookieEJB: superuser
      16:18:02,549 ERROR [stderr] (default task-4) SessionInfoEJB: superuser
      16:18:02,650 ERROR [stderr] (Timer-5) SessionInfoEJB: anonymous
      16:18:31,789 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,794 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,805 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,818 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,829 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,840 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,851 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,863 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,875 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,886 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,898 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,909 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,941 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:18:31,946 ERROR [stderr] (Timer-7) SessionInfoEJB: anonymous
      16:19:47,924 ERROR [stderr] (Timer-10) UserCookieEJB: anonymous
      16:19:47,926 ERROR [stderr] (Timer-10) UserCookieEJB: anonymous
      
        • 1. Re: Trouble getting principal name in EJB
          sfcoy

          Timers do not inherit the security context from whatever scheduled it.

           

          If you really need the identity of the user that scheduled the timer then you must pass it along in the serializable "info" parameter when the timer is created.

          • 2. Re: Trouble getting principal name in EJB
            tbronzan

            There were no timers, or shouldn't be where the ejb was being used in the output messages.  The UI was being built after logging in to the application.  Basically the code that made the call to the ejb is responsible for laying out the components based on the user "cookies" in the database.  It's a straight local ejb lookup and method call.  This code works perfectly fine when run on Glassfish 3.1.2.  We're currently migrating to Wildfly.

            • 3. Re: Re: Trouble getting principal name in EJB
              sfcoy

              This:

              16:18:02,650 ERROR [stderr] (Timer-5) SessionInfoEJB: anonymous

              looks like a timer to me...

              • 4. Re: Re: Trouble getting principal name in EJB
                tbronzan

                Ok I found the problem and you're right it's because of a Timer.  Unfortunately the timer is started outside the ejb container so it's a java.util.Timer so I don't know if I can use the TimerService to create one instead.  I'm not sure why a timer is being used where it is but I'll probably have to remove it.  However, knowing I need to pass the security context in will help me in a couple other areas.

                 

                Thanks.

                 

                EDIT:  Do you know if there is a way to get the security context into a java.util.Timer?  There's a few other places we use timers and they're not as easy to rip out like the problem area in the original post.

                • 5. Re: Trouble getting principal name in EJB
                  sfcoy

                  You will still have the same problem if you use the EJB timer service.

                   

                  If it's a one-shot timer you might try using javax.ejb.Asynchronous method on an EJB, which propagates the security context.

                  • 6. Re: Trouble getting principal name in EJB
                    tbronzan

                    Unfortunately the timer is not one shot and it's being used outside of an ejb.  What happens is in the web container a timer is created that goes off on a set interval to update a section of the page.  The code that is executed when the timer times out makes a call to an ejb to get the current information to display.  Because the update happens via a timer the security context isn't passed through as you pointed out.  Since it's outside of the ejb container it is a java.util.Timer which doesn't make use of the javax.ejb.TimerConfig so there doesn't seem to be a way to pass in the security context so the ejb call will succeed.

                     

                    It seems the real problem here is a design issue that is exposed with the switch to WildFly. I guess using a timer to update the UI is not the way to do things.

                     

                    On a side note, what's the deal with only being able to post once an hour?  It makes it really difficult to participate in this and other discussions.

                    • 7. Re: Trouble getting principal name in EJB
                      sfcoy

                      Actually, I've just remembered that this is JavaEE 7.

                       

                      So you have access to JSR 236: Concurrency Utilities for Java™ EE. Creating new threads using this *will* propagate your security context.

                      • 8. Re: Re: Trouble getting principal name in EJB
                        emmartins

                        As sfcoy mentioned you may use instead the EE Concurrency Utilities, more specifically you may replace usage of java.util.Timer with the ManagedScheduledExecutorService's default instance, obtainable from JNDI (java:comp/ManagedScheduledExecutorService). Your code can abstract the usage in Java SE or Java EE too, by using the common java.util.concurrent.ScheduledExecutorService interface.

                         

                        Anyway, one question that could also be asked, is what interest has such context information on a timer task, I mean why the need to always obtain it, since conceptually it will always be the same, thus why not collect it right away when setting the timer...