Outjection with scope session corrupts sessions of other users
rehdie Jan 25, 2010 4:24 PMHi everybody,
in the last 2 weeks I struggled with a problem, which was caused by a problem with outjection.Here are the details (sorry for the length of this post):
Environment: jBoss 5.1.0, apache web-server, Java 6, JVM: jrockit, operating system: red hat linux, currently we have a single jBoss instance. The application is deployed as an exploded ear-file which contains 2 .war-files.
Website: www.skiline.cc (currently more than 100.000 registered users, if you are crazy about skiing, watch out that site :-))
We did outject the logged in user to the session scope. Here is an excerpt of the source-code:
@Stateless @Name("authenticator") public class AuthenticatorBean implements Authenticator { @In private Identity identity; @In private Credentials credentials; @Out(required=false) private User loggedInUser; @In private UserService userService; public boolean authenticate() { User user = userService.getUserByUserName(credentials.getUsername()); // do verification of username and password .... loggedInUser = user; log.info("User {0}/{1} logged in. IP={2}, Session: {3}", user.getUserName(), user.getId(), JsfUtil.getRemoteIPAddress(), JsfUtil.getSessionId()); return true; } }
JsfUtil.getRemoteIPAddress() and JsfUtil.getSessionId() returns the remote IP address and session ID of the current request using FacesContext.getCurrentInstance().getExternalContext().
What happened? The user was outjected to more than one session and we had problems with corrupted data (and we got a lot of complaints by users and ski-lift operators).
After a lot of debugging and logging I changed the code to set the user to session directly without outjection:
@Stateless @Name("authenticator") public class AuthenticatorBean implements Authenticator { @In private Identity identity; @In private Credentials credentials; @In private UserService userService; public boolean authenticate() { User user = userService.getUserByUserName(credentials.getUsername()); // do verification of username and password .... Contexts.getSessionContext().set("loggedInUser", user); log.info("User {0}/{1} logged in. IP={2}, Session: {3}", user.getUserName(), user.getId(), JsfUtil.getRemoteIPAddress(), JsfUtil.getSessionId()); return true; } }
This change solved our problem (no corrupted sessions anymore).
---------------
To find this problem, I've implemented a HttpSessionAttributeListener, which observed the session-attribute loggedInUser
. Everytime this attribute was added, modified or removed, a log record including a stacktrace was written (to find out, where the attribute change came from).
Here is the critical part from the logfile:
The logging written by the AuthenticatorBean:
2010-01-23 00:00:39,623 INFO [cc.skiline.service.security.AuthenticatorBean] User pirelli/8a678153262800d801262961467c085a logged in. IP=213.47.201.95, Session: 3B2D79845DD8DDC39D0D94FD26A51924.skilinenode1
The logging written by the HttpSessionAttributeListener:
2010-01-23 00:00:39,623 INFO [cc.skiline.gui.security.SessionListener] (ajp-10.231.1.211-8109-6) loggedInUser 8a678153262800d801262961467c085a/pirelli added to session 3B2D79845DD8DDC39D0D94FD26A51924.skilinenode1 (identity 1799950454, context: ) java.lang.Exception at cc.skiline.gui.security.SessionListener.attributeAdded(SessionListener.java:51) at org.apache.catalina.session.StandardSession.setAttribute(StandardSession.java:1366) at org.apache.catalina.session.StandardSession.setAttribute(StandardSession.java:1258) at org.apache.catalina.session.StandardSessionFacade.setAttribute(StandardSessionFacade.java:130) at com.sun.faces.context.SessionMap.put(ExternalContextImpl.java:971) at org.jboss.seam.contexts.BasicContext.set(BasicContext.java:84) at org.jboss.seam.Component.outjectAttribute(Component.java:1806) at org.jboss.seam.Component.outjectAttributes(Component.java:1755) at org.jboss.seam.Component.outject(Component.java:1608) ...... at $Proxy779.authenticate(Unknown Source) ...... at org.jboss.seam.security.jaas.SeamLoginModule.login(SeamLoginModule.java:109) ...... at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769) at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186) at javax.security.auth.login.LoginContext$5.run(LoginContext.java:706) at javax.security.auth.login.LoginContext.invokeCreatorPriv(LoginContext.java:703) at javax.security.auth.login.LoginContext.login(LoginContext.java:575) at org.jboss.seam.security.Identity.authenticate(Identity.java:344) at org.jboss.seam.security.Identity.authenticate(Identity.java:332) at org.jboss.seam.security.Identity.login(Identity.java:259) .....
and 2 seconds later you can see, that the same user is outjected to a completely different session (we had around 300 of these corrupted sessions per day!).
2010-01-23 00:00:41,289 INFO [cc.skiline.gui.security.SessionListener] (ajp-10.231.1.211-8109-6) loggedInUser 8a678153262800d801262961467c085a/pirelli added to session A0A14884FB420D8A24E1C5821DC20D7D.skilinenode1 (identity 1864324221, context: ) java.lang.Exception at cc.skiline.gui.security.SessionListener.attributeAdded(SessionListener.java:51) at org.apache.catalina.session.StandardSession.setAttribute(StandardSession.java:1366) at org.apache.catalina.session.StandardSession.setAttribute(StandardSession.java:1258) at org.apache.catalina.session.StandardSessionFacade.setAttribute(StandardSessionFacade.java:130) at com.sun.faces.context.SessionMap.put(ExternalContextImpl.java:971) at org.jboss.seam.contexts.BasicContext.set(BasicContext.java:84) at org.jboss.seam.Component.outjectAttribute(Component.java:1806) at org.jboss.seam.Component.outjectAttributes(Component.java:1755) at org.jboss.seam.Component.outject(Component.java:1608) ... at $Proxy779.authenticate(Unknown Source) ... at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769) at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186) at javax.security.auth.login.LoginContext$5.run(LoginContext.java:706) at javax.security.auth.login.LoginContext.invokeCreatorPriv(LoginContext.java:703) at javax.security.auth.login.LoginContext.login(LoginContext.java:575) at org.jboss.seam.security.Identity.authenticate(Identity.java:344) at org.jboss.seam.security.Identity.authenticate(Identity.java:332) at org.jboss.seam.security.Identity.login(Identity.java:259) .....
Does anybody have an idea, what's going on here? That's an absolute showstopper, so util I know, what's going on here, I won't use outjection anymore (espacially outjection to session scope)!