9 Replies Latest reply: May 28, 2012 4:02 PM by Roberto Rodrigues RSS

Outjection with scope session corrupts sessions of other users

Dieter Rehbein Newbie

Hi 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)!

  • 1. Re: Outjection with scope session corrupts sessions of other users
    Nikos Paraskevopoulos Novice

    Hello,


    This weird behaviour might be caused from the fact that AuthenticatorBean is @Stateless without any explicit scope setting. Therefore it lives in the stateless scope, which, I believe, is the global scope! So you were outjecting a component with session semantics to the global scope (ouch :)


    I hope this is the correct explanation, or Seam has a serious bug...

  • 2. Re: Outjection with scope session corrupts sessions of other users
    Arbi Sookazian Master

    from Seam 2.1.1.GA API for @Out:



    Specifies the scope to outject to. If no scope is explicitly specified, the default scope depends upon whether the value is an instance of a Seam component. If it is, the component scope is used. Otherwise, the scope of the component with the @Out attribute is used. But if the component scope is STATELESS, the EVENT scope is used.

    So in this case the Seam container is outjecting to EVENT scope b/c a SLSB Seam component is STATELESS scope by default.


    You can try outjecting explicitly to SESSION scope like this:


    @Out(required=false,scope=ScopeType.SESSION)
       private User loggedInUser;


    Otherwise, this may very well be a bug...

  • 3. Re: Outjection with scope session corrupts sessions of other users
    Dieter Rehbein Newbie

    I'm sorry, but the source-excerpt was wrong, the original code before the change looked like this:




    ...
       @Out(required = false, scope = ScopeType.SESSION)
       private User loggedInUser;
    ....



    So IMHO the scope was specified correctly.

  • 4. Re: Outjection with scope session corrupts sessions of other users
    Dieter Rehbein Newbie

    In the stacktrace posted above you can see, that the user was set to a session, because a stacktrace was logged by HttpSessionAttributeListener:



            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)
    





    so it was not outjected to event scope but to a session (but unfortunately sometimes to a wrong session).

  • 5. Re: Outjection with scope session corrupts sessions of other users
    Adam Wells Newbie
    We have encountered a similar problem.

    JBoss 4.2.3, Seam 2.1.2, Java 5

    We have a Flex application that communicates with a Seam app via GraniteDS.  After logging in, we store the session details in a client side object.  We found that on at least one occasion, a client call from Flex to Seam was matched up with the wrong Seam session - the result was that the user got to see someone else's data.

    The mismatched session was created many hours earlier in the day - ie it was not concurrent with the problem session.

    We have a SLSB(ScopeType.SESSION) that outjects(        @Out(required = true, scope = ScopeType.SESSION)
    ) the object that contains user session details.

    We will try the workaround suggested above and keep an eye on it.

    Should we consider upgrade to Seam 2.2? JBoss 5/6?
  • 6. Re: Outjection with scope session corrupts sessions of other users
    Roberto Rodrigues Newbie

    I´m having the same problem.

     

    It´s difficult because the problem doesn´t happens with me.

     

    I will try your workaround and will be back to report.

     

    Thanks for sharing!

  • 7. Re: Outjection with scope session corrupts sessions of other users
    Emir Calabuch Newbie

    IMHO, the problem is the SLSB lifecycle: you shouldn't hold state in a SLSB (as its name suggests). There's the chance that the data you put in the SLSB's fields is maintained there and, when the SLSB is reused, it stays there. I think the problem is user A logs in (field loggedInUser points to UserA) and then user B logs in. The SLSB is recycled for User B, so he finds loggedInUser still pointing to the previous logged in user. Since User B is unable to log in, loggedInUser does not get overriden and Seam outjects the old value.

     

    This perhaps could be replicated in a test environment by reducing the SLSB pool size to 1 element...

     

    Seam's bijection is a powerful feature but I don't think it mixes very well with SLSBs because it tends to make you use fields in your SLSB, which implies some data could be leaked (SLSBs are pooled to reduce creation overhead so two users could use the same instance of the SLSB).

     

    After outjection, Seam does try to do some cleanup (termed "disinjection"), but it only cleans up fields with "@In", not "@Out" (don't ask me why, I have yet to understand the reason, but that's how it just works). So in this case the "loggedInUser" field keeps is not disinjected after outjection and therefore keeps it value. To avoid the problem, just use "@In" as well as "@Out" in loggedInUser. Anyway in these cases I tend to prefer the Seam API (Contexts.getSessionContext.set(...)) because I dislike SLSBs having private fields at all (except for things like loggers and stuff).

  • 8. Re: Outjection with scope session corrupts sessions of other users
    Roberto Rodrigues Newbie

    Thanks for considerations Emir.

     

    I´m still looking this problem. I´m not using SLSB. My autenticator is in event scope:

     

    <component name="auth" class="com.somepackage.auth.SomeAuthenticator" scope="event" auto-create="true"/>
    

     

    I tried wih:

    @Out(required = false, scope = ScopeType.SESSION)
    private User user;
    

     

    And with:

    Contexts.getSessionContext().set("user", user);
    

     

    It works well for me. tested with a few machines on the network and logging in different browsers with different users.

    However, some clients where also several people log in, it seems that all share the same user session.

    Checking the server log, all is right with different sessions ID. Like this:

    user1 200.19.200.5 Session: 02EFA238223E38E1DD3CEA3A01CEB9CF

    user2 200.19.200.5 Session: 7FE1865EDB026ACA5C8E3DCB704C219A

     

    But they see others users

  • 9. Re: Outjection with scope session corrupts sessions of other users
    Roberto Rodrigues Newbie

    My problem wasn´t in my app or Seam.

     

    My client has several offices in different cities that use the same firewall. The problem was in the firewall cache.