2 Replies Latest reply on Dec 30, 2011 9:31 AM by arjan tijms

    Timeout method's security context not correctly implemented?

    arjan tijms Novice

      Hi,

       

      Section 18.2.5.3 of the EJB 3.1 spec gives the following requirement for the Timeout callback method:

      Since a timeout callback method is an internal method of the bean class, it has no client security context. When getCallerPrincipal is called from within a timeout callback method, it returns the container’s representation of the unauthenticated identity.

       

      In JBoss AS 7 and 6 this is not what happens. The security context within the timeout callback method seems to be dependent on the one that was active when the timer was scheduled:

       

      • If a principal was authenticated in the web module on AS 6, the callback will have the roles of said principal. Exception on AS 7.
      • If an @RunAS annotation was used on a Servlet, an exception will result when the security context is referenced
      • If an @RunAS annotation was used on a Message Driven Bean, an exception will result when the security context is referenced

       

       

      Consider the following example:

       

      @Stateless
      @DeclareRoles({ "Foo" })
      @SecurityDomain("something")
      public class RolesTestEJB {
      
          @Resource
          private TimerService timerService;
      
          @Resource
          private SessionContext sessionContext;
      
          @RolesAllowed({ "Foo" })
          public void securedMethod() {
              System.out.println("In secured RolesTestEJB.securedMethod");
              System.out.println("RolesTestEJB.isCallerInRole( \"Foo\" ): " + sessionContext.isCallerInRole("Foo") + " (expect 'true')");
              System.out.println("Principal is " + sessionContext.getCallerPrincipal());
      
              timerService.createSingleActionTimer(new Date(new Date().getTime() + 1000), new TimerConfig(null, false));
          }
      
          @Timeout
          public void timeoutMethod(Timer timer) {
              System.out.println("In secured RolesTestEJB.timeoutMethod");
              System.out.println("RolesTestEJB.isCallerInRole( \"Foo\" ): " + sessionContext.isCallerInRole("Foo") + " (expect 'true')");
              System.out.println("Principal is " + sessionContext.getCallerPrincipal());
          }
      
      }
      

       

       

      When testing this on Glassfish 3.1.1, the following results:

       

      Call originates from @RunaAS Servlet:

      INFO: RolesTestServlet.isUserInRole( "Foo" ): false (expect 'false')
      INFO: In secured RolesTestEJB.securedMethod
      INFO: RolesTestEJB.isCallerInRole( "Foo" ): true (expect 'true')
      INFO: Principal is bar
      
      INFO: In secured RolesTestEJB.timeoutMethod
      INFO: RolesTestEJB.isCallerInRole( "Foo" ): false (expect 'false')
      INFO: Principal is ANONYMOUS
      
      

       

       

      Call originates from @RunAS Message Driven Bean:

      INFO: RolesTestMDB.onMessage
      INFO: In secured RolesTestEJB.securedMethod
      INFO: RolesTestEJB.isCallerInRole( "Foo" ): true (expect 'true')
      INFO: Principal is bar
      
      INFO: In RolesTestEJB.timeoutMethod
      INFO: RolesTestEJB.isCallerInRole( "Foo" ): false (expect 'false')
      INFO: Principal is ANONYMOUS
      
      

       

       

      Call originates from authenticated Servlet (BASIC, file realm):

      INFO: RolesTestServletAuthenticated.isUserInRole( "Foo" ): true (expect 'true')
      INFO: In secured RolesTestEJB.securedMethod
      INFO: RolesTestEJB.isCallerInRole( "Foo" ): true (expect 'true')
      INFO: Principal is bar
      
      INFO: In RolesTestEJB.timeoutMethod
      INFO: RolesTestEJB.isCallerInRole( "Foo" ): false (expect 'false')
      INFO: Principal is ANONYMOUS
      
      

      ("bar" is the default principle mapped to the role "Foo")

       

       

      When testing on JBoss AS 7, the following results:

       

      Call originates from @RunAS Message Driven Bean (Servlet output is similar)

      INFO RolesTestMDB.onMessage
      INFO In secured RolesTestEJB.securedMethod
      INFO RolesTestEJB.isCallerInRole( "Foo" ): true (expect 'true')
      INFO Principal is [roles=[Foo],principal=run-as-principal]
      
      INFO  In RolesTestEJB.timeoutMethod
      ERROR [org.jboss.as.ejb3.timerservice.mk2.task.TimerTask] (pool-18-thread-1) Error invoking timeout for timer: [id=a775fdb3-2498-4cef-9d63-b8924a356267 timedObjectId=RolesTestEJB auto-timer?:false persistent?:false timerService=org.jboss.as.ejb3.timerservice.mk2.TimerServiceImpl@50a52ae9 initialExpiration=Sun Nov 27 13:51:12 CET 2011 intervalDuration(in milli sec)=0 nextExpiration=null timerState=IN_TIMEOUT: java.lang.RuntimeException: javax.ejb.EJBException: java.lang.IllegalStateException: No security context established
                at org.jboss.as.ejb3.component.EjbComponentInstance.invokeTimeoutMethod(EjbComponentInstance.java:76) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                [...]
      Caused by: javax.ejb.EJBException: java.lang.IllegalStateException: No security context established
                at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:160) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                [...]
      Caused by: java.lang.IllegalStateException: No security context established
                at org.jboss.as.security.service.SimpleSecurityManager.getCallerPrincipal(SimpleSecurityManager.java:80) [jboss-as-security-7.0.2.Final.jar:7.0.2.Final]
                at org.jboss.as.ejb3.component.EJBComponent.getCallerPrincipal(EJBComponent.java:163) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                at org.jboss.as.ejb3.component.session.SessionInvocationContextInterceptor$CustomSessionInvocationContext.getCallerPrincipal(SessionInvocationContextInterceptor.java:94) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                at org.jboss.as.ejb3.context.base.BaseInvocationContext.isCallerInRole(BaseInvocationContext.java:146) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                at org.jboss.as.ejb3.context.base.BaseEJBContext.isCallerInRole(BaseEJBContext.java:111) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                at com.example.RolesTestEJB.timeoutMethod(RolesTestEJB.java:40)          
      

       

       

      Call originates from authenticated Servlet (BASIC as well as programmatic login, using properties login module):

      INFO RolesTestServletAuthenticated.isUserInRole( "Foo" ): true (expect 'true')
      INFO In secured RolesTestEJB.securedMethod
      INFO RolesTestEJB.isCallerInRole( "Foo" ): true (expect 'true')
      INFO Principal is guest
      
      INFO In RolesTestEJB.timeoutMethod
      14:56:22,296 ERROR [org.jboss.as.ejb3.timerservice.mk2.task.TimerTask] (pool-5-thread-1) Error invoking timeout for timer: [id=651bdadb-d260-4857-9964-62f0b979d6b1 timedObjectId=RolesTestEJB auto-timer?:false persistent?:false timerService=org.jboss.as.ejb3.timerservice.mk2.TimerServiceImpl@8561a10 initialExpiration=Sun Nov 27 14:56:22 CET 2011 intervalDuration(in milli sec)=0 nextExpiration=null timerState=IN_TIMEOUT: java.lang.RuntimeException: javax.ejb.EJBException: java.lang.IllegalStateException: No security context established
                at org.jboss.as.ejb3.component.EjbComponentInstance.invokeTimeoutMethod(EjbComponentInstance.java:76) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                [...]
      Caused by: javax.ejb.EJBException: java.lang.IllegalStateException: No security context established
                at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:160) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                [...]
      Caused by: java.lang.IllegalStateException: No security context established
                at org.jboss.as.security.service.SimpleSecurityManager.getCallerPrincipal(SimpleSecurityManager.java:80) [jboss-as-security-7.0.2.Final.jar:7.0.2.Final]
                at org.jboss.as.ejb3.component.EJBComponent.getCallerPrincipal(EJBComponent.java:163) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                at org.jboss.as.ejb3.component.session.SessionInvocationContextInterceptor$CustomSessionInvocationContext.getCallerPrincipal(SessionInvocationContextInterceptor.java:94) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                at org.jboss.as.ejb3.context.base.BaseInvocationContext.isCallerInRole(BaseInvocationContext.java:146) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                at org.jboss.as.ejb3.context.base.BaseEJBContext.isCallerInRole(BaseEJBContext.java:111) [jboss-as-ejb3-7.0.2.Final.jar:7.0.2.Final]
                at com.example.RolesTestEJB.timeoutMethod(RolesTestEJB.java:40)
      

      (simplified logger to not log time and thread name)

       

       

      When testing on JBoss AS 6, the following results:

       

      Call originates from @RunAS Message Driven Bean (Servlet output is similar)

      INFO  RolesTestMDB.onMessage
      INFO  In secured RolesTestEJB.securedMethod
      INFO  RolesTestEJB.isCallerInRole( "Foo" ): true (expect 'true')
      INFO  Principal is [roles=[Foo],principal=anonymous]
      
      INFO  In RolesTestEJB.timeoutMethod
      INFO  RolesTestEJB.isCallerInRole( "Foo" ): false (expect 'false')
      ERROR [org.jboss.ejb3.timerservice.mk2.task.TimerTask] Error invoking timeout for timer: [id=28350da9-e963-43d9-86b2-197d684f745d timedObjectId=jboss.j2ee:jar=rolesAllowedTest.war,name=RolesTestEJB,service=EJB3 auto-timer?:false persistent?:false timerService=org.jboss.ejb3.timerservice.mk2.TimerServiceImpl@4de9150a initialExpiration=Sun Nov 27 10:29:52 CET 2011 intervalDuration(in milli sec)=0 nextExpiration=null timerState=IN_TIMEOUT: javax.ejb.EJBException: java.lang.IllegalStateException: No valid security context for the caller identity
                at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.handleExceptionInOurTx(CMTTxInterceptor.java:183) [:0.0.2]
                at org.jboss.ejb3.tx2.impl.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:251) [:0.0.2]
              [...]
      Caused by: java.lang.IllegalStateException: No valid security context for the caller identity
                at org.jboss.ejb3.EJBContextImpl.getCallerPrincipal(EJBContextImpl.java:143) [:1.7.21]
                at com.example.RolesTestEJB.timeoutMethod(RolesTestEJB.java:41) [:]
                [...]
      

       

       

      Call originates from authenticated Servlet (BASIC as well as programmatic login, using properties login module):

      INFO RolesTestServletAuthenticated.isUserInRole( "Foo" ): true (expect 'true')
      INFO In secured RolesTestEJB.securedMethod
      INFO RolesTestEJB.isCallerInRole( "Foo" ): true (expect 'true')
      INFO Principal is guest
      
      INFO In RolesTestEJB.timeoutMethod
      INFO RolesTestEJB.isCallerInRole( "Foo" ): true (expect 'false')
      INFO Principal is [roles=[Foo],principal=anonymous]