EJB security propagation issue when moving from JBoss 3.0.4
mescalito Mar 16, 2004 1:44 PMHi,
At the moment I'm moving all our team's applications from JBoss 3.0.4 to JBoss 3.2.3. Everything is done, apart from the following problem, which is really killing me.
We've got an application with 'standard' (I mean, nothing special or unusual) Web and EJB tiers, which both run under JAAS, under the same security domain (form-based authentication, custom LoginModule derived from DatabaseServerLoginModule with minimal amendments). It perfectly works on JBoss 3.0.4 (for at least a year and 3 production releases), but when deployed on JBoss 3.2.3, security context (propagated from Web actions) dissappears within EJB layer. I've put some logging into the LoginModule and the code where I invoke EJB from Web tier (below in bold).
18:14:40,137 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking login() 18:14:40,137 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking getUsernameAndPassword()= [my_login, <<my_password>>] 18:14:40,153 INFO [com.smth.portal.security.auth.PortalLoginModule] getUsernameAndPassword()= [my_login, <<my_password>>] 18:14:40,168 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking validatePassword("<<my_password>>, <<my_password>>") 18:14:40,184 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking commit(): true 18:14:40,231 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking login() 18:14:40,231 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking getUsernameAndPassword()= [my_login, <<my_password>>] 18:14:40,247 INFO [com.smth.portal.security.auth.PortalLoginModule] getUsernameAndPassword()= [my_login, <<my_password>>] 18:14:40,262 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking validatePassword("<<my_password>>, <<my_password>>") 18:14:40,278 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking commit(): true 18:14:40,293 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking logout() 18:14:40,387 INFO [STDOUT] IN WEB ACTION: SecurityAssociation.getPrincipal() = my_login, getCredential() = [C@e628d8 18:14:40,403 INFO [STDOUT] IN EJB LAYER: context.context.getCallerPrincipal().getName()=my_login 18:14:40,403 INFO [STDOUT] IN EJB LAYER: SecurityAssociation.getPrincipal() = null, getCredential() = null 18:14:40,434 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking login() 18:14:40,434 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking getUsernameAndPassword()= [null, null] 18:14:40,450 INFO [com.smth.portal.security.auth.PortalLoginModule] getUsernameAndPassword()= [null, null] 18:14:40,450 INFO [com.smth.portal.security.auth.PortalLoginModule] Invoking abort() 18:14:40,466 ERROR [org.jboss.ejb.plugins.SecurityInterceptor] Authentication exception, principal=null 18:14:40,466 ERROR [org.jboss.ejb.plugins.LogInterceptor] EJBException, causedBy: java.lang.SecurityException: Authentication exception, principal=null at org.jboss.ejb.plugins.SecurityInterceptor.checkSecurityAssociation(SecurityInterceptor.java:164) at org.jboss.ejb.plugins.SecurityInterceptor.invokeHome(SecurityInterceptor.java:81) at org.jboss.ejb.plugins.LogInterceptor.invokeHome(LogInterceptor.java:120) at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invokeHome(ProxyFactoryFinderInterceptor.java:93) at org.jboss.ejb.EntityContainer.internalInvokeHome(EntityContainer.java:483) at org.jboss.ejb.Container.invoke(Container.java:720) at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invokeHome(BaseLocalProxyFactory.java:293) at org.jboss.ejb.plugins.local.LocalHomeProxy.invoke(LocalHomeProxy.java:110) at $Proxy246.findByUserId(Unknown Source) at com.smth.app.alm.object.task.ejb.TaskFacadeSL.getTaskList(TaskFacadeSL.java:247) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at org.jboss.ejb.StatelessSessionContainer$ContainerInterceptor.invoke(StatelessSessionContainer.java:683) at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.invoke(CachedConnectionInterceptor.java:185) at org.jboss.ejb.plugins.StatelessSessionInstanceInterceptor.invoke(StatelessSessionInstanceInterceptor.java:72) at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:84) at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:267) at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:128) at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:118) at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:191) at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122) at org.jboss.ejb.StatelessSessionContainer.internalInvoke(StatelessSessionContainer.java:331) at org.jboss.ejb.Container.invoke(Container.java:700) at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invoke(BaseLocalProxyFactory.java:375) at org.jboss.ejb.plugins.local.StatelessSessionProxy.invoke(StatelessSessionProxy.java:83) at $Proxy387.getTaskList(Unknown Source) at com.smth.app.alm.web.actions.TaskAction.performListAction(TaskAction.java:118) ...
And the source code:
In Web action:
TaskFacade facade = BeanHelper.getTaskFacade(); String msg; try { msg = "SecurityAssociation.getPrincipal() = " +SecurityAssociation.getPrincipal() + ", " + "getCredential() = " + SecurityAssociation.getCredential(); } catch(IllegalStateException ie) { msg = null; } System.out.println("IN WEB ACTION: "+msg); request.setAttribute("task.list", facade.getTaskList());
and in EJB tier:
public Collection getTaskList() throws ApplicationException { String username; try { username = "context.context.getCallerPrincipal().getName()="+context.getCallerPrincipal().getName(); } catch(IllegalStateException ie) { username = null; } System.out.println("IN EJB LAYER: " + username); String msg = "SecurityAssociation.getPrincipal() = " + SecurityAssociation.getPrincipal() + ", " + "getCredential() = " + SecurityAssociation.getCredential(); System.out.println("IN EJB LAYER: " + msg); ... }
Method permissions for EJBs are declared in the same way for the same role:
<security-role> <role-name>alm_user</role-name> </security-role> <method-permission> <role-name>alm_user</role-name> <method> <ejb-name>TaskFacade</ejb-name> <method-name>*</method-name> </method> ... <method> <ejb-name>Task</ejb-name> <method-name>*</method-name> </method> </method-permission>
So if you take a look at the bold text in log message, you may notice, that the first call to EJB layer goes fine, and the EJB gets a context with Principal set up correctly, but with nullfied SecurityAssociation attributes. The same .EAR-file, deployed on JBoss 3.0.4, has non-null SecurityAssociation attributes in the same place.
Obviously, when the first EJB in the invocation chain tries to make a call to the second one ($Proxy246.findByUserId(Unknown Source)) with nullified SecurityAssociation attributes, it gets stuck in SecurityInterceptor.
Could please somebody explain to me, at which stage and why SecurityAssociation.getPrincipal() and SecurityAssociation.getCredential() are being nullified in JBoss 3.2.3 (and prevent application to work correctly), but remain the same in JBoss 3.0.4?
I've checked through virtually all the possible explanations (I've also got the same problem with other apps, which survived through JBoss 2.4.x, Jboss 3.0.x), so I desperately need some JBoss guru to find out an answer.
Thanks in advance!
Stan