Timeout method's security context not correctly implemented?
atijms Nov 27, 2011 4:52 PMHi,
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]