0 Replies Latest reply on Jan 6, 2014 10:04 AM by jkronegg

    Credentials still cached in ThreadLocal after logout

    jkronegg

      Hello,

       

      First of all, happy new year to all the JBoss teams and JBoss users. I wish you more productivity and less bugs.

       

      I'm running a web application on JBoss AS 5.2 and I've got some issues with the logout process.

       

      The web application has a custom web authentication method (a custom SignonServlet doing the new WebAuthentication().login(username, password), which calls the underlying LoginModule (we use org.jboss.security.auth.spi.LdapLoginModule with a LDAP-RACF server, configured in login-config.xml).

      When a new session is created (HttpSessionListener), an EJB is accessed locally:

       

      public void sessionCreated(HttpSessionEvent arg0) {
          ...
          InitialContext ic = new InitialContext();
          Object ejb_stub = ic.lookup("MyEJB");
          MyEjb myEjb = (MyEjbInterface)PortableRemoteObject.narrow(ejb_stub, MyEjbInterface.class);
          myEjb.myMethod();
          ...
      }
      
      

       

      The EJB is configured with "all authenticated users" security policy in the EJB EAR's META-INF/jboss-app.xml (i.e. any logged user can call the EJB; anonymous users that are not logged on can also call the EJB):

       

      <jboss-app>
          ...
      
           <security-domain>java:/jaas/MyPortal</security-domain>
          ...
      </jboss-app>
      

       

      The security domain is configured as follow in the login-context.xml:

       

      <policy>
          <application-policy name="MyLdapRealm">
              <authentication>
                  <login-module code="org.jboss.security.auth.spi.LdapLoginModule" flag="required">
                      <module-option name="java.naming.factory.initial">com.sun.jndi.ldap.LdapCtxFactory</module-option>
                      <module-option name="java.naming.provider.url">ldap://MY_IP_ADDRESS:MY_PORT/</module-option>
                      <module-option name="java.naming.security.authentication">simple</module-option>
                      <module-option name="principalDNPrefix">racfid=</module-option>
                      <module-option name="principalDNSuffix">,profiletype=user,o=mycompany</module-option>
                      <module-option name="allowEmptyPasswords">false</module-option>
                      <module-option name="searchTimeLimit">60000</module-option>
                      <module-option name="password-stacking">useFirstPass</module-option>
                      <module-option name="throwValidateError">true</module-option>
                  </login-module>
             </authentication>
         </application-policy>
         <application-policy name="MyPortal" extends="MyLdapRealm">
              <authentication>
                  <login-module code="org.jboss.security.auth.spi.IdentityLoginModule" flag="required">
                      <module-option name="principal">all_authenticated</module-option>
                      <module-option name="roles">myRole</module-option>
                      <module-option name="password-stacking">useFirstPass</module-option>
                  </login-module>
              </authentication>
         </application-policy>
         ...
      </policy>
      

       

       

      When the user logs out, a signoff.jsp page is called:

       

      ...
      System.out.println("signoff.jsp: before session invalidate: sessionId="+session.getId());
      session.invalidate(); // invalidates the session and calls the underlying `LoginModule`s
      System.out.println("signoff.jsp: aftersession invalidate: sessionId="+session.getId());
      HttpSession newSession = request.getSession(true); // recreates a new session
      System.out.println("signoff.jsp: after new session: sessionId="+newSession.getId());
      ...
      
      

       

      The issue is that session.invalidate() invalidates the session but does not clear the credentials stored in the SecurityContext of the current Thread. Then, when the new session is created, the HttpSessionListener makes a new access to `MyEjb` using the authentication parameters stored in the ThreadLocal when I expect to have an EJB access without authentication since the EJB is not secured and the user has not logged yet.

       

      I added some logging in the JBoss's LoginModule to show this behavior:

       

      10:22:56,053 ERROR [STDERR] 13-12-20 10:22:56,053 [http-0.0.0.0-8080-3] [INFO] MyRequestListener: url=/myContext/signoff.jsp

      ***** here is the session.invalidate

      10:22:56,099 INFO  [STDOUT] signoff.jsp: before session invalidate: sessionId=E8298944C9362FB49DE627D3C385E8B2.srv1

      10:22:56,099 INFO  [UsernamePasswordLoginModule] logout: this=org.jboss.security.auth.spi.LdapLoginModule@4fbb8317, subject.principal=myPrincipal

      10:22:56,099 INFO  [STDOUT] signoff.jsp: after session invalidate: sessionId=E8298944C9362FB49DE627D3C385E8B2.srv1

      10:22:56,099 INFO  [UsernamePasswordLoginModule] login: this=org.jboss.security.auth.spi.LdapLoginModule@7faa5e5a

      10:22:56,115 INFO  [LdapLoginModule] login: loginOk=false

       

      ***** here is the new session creation and the EJB access

      10:22:56,115 INFO  [UsernamePasswordLoginModule] login (login required): username=myUsername, password=myPassword, callbackClass=class javax.security.auth.login.LoginContext$SecureCallbackHandler

      10:22:56,115 INFO  [UsernamePasswordLoginModule] no identity => requiers password validation

      10:22:56,115 INFO  [LdapLoginModule] validatePassword: inputPassword=myPassword, expectedPassword=

      10:22:56,115 INFO  [LdapLoginModule] createLdapInitContext: username=myUsername, credential=myPassword

      10:22:56,115 INFO  [IdentityLoginModule] login: loginOk=true

      10:22:56,115 INFO  [STDOUT] signoff.jsp: after new session: sessionId=CC09AC10AD30B431413756E05D6BD54F.srv1

       

      After digging a lot of JBoss authentication code, I tried to clear the ThreadLocal SecurityContext when the session is invalidated in the HttpSessionListener:

       

      public void sessionDestroyed(HttpSessionEvent arg0) {
          ...
          org.jboss.security.SecurityContextAssociation.clearSecurityContext(); // remove the ThreadLocal SecurityContext
          ...
      }
      
      

       

      This produces the expected result (i.e. when the session is created, the EJB access in the HttpSessionListener does not produce an authentication) :

       

      ***** here is the session.invalidate

      17:08:47,638 ERROR [STDERR] 13-12-20 17:08:47,638 [http-0.0.0.0-8080-3] [INFO] MyRequestListener: url=/myContext/signoff.jsp

      17:08:47,638 INFO  [STDOUT] signoff.jsp: before session invalidate: sessionId=DAF4D800ACBC6C2C09E38674DBC37E05.srv1

      17:08:47,642 ERROR [STDERR] 13-12-20 17:08:47,642 [http-0.0.0.0-8080-2] [INFO] bper.util.common.JBossAsUtils: logoutCurrentUser: removing SecurityContext from JBoss ThreadLocal cache...

      17:08:47,644 INFO  [STDOUT] signoff.jsp: after session invalidate: sessionId=DAF4D800ACBC6C2C09E38674DBC37E05.srv1

       

      ***** here is the new session creation and the EJB access

      17:08:47,646 INFO  [STDOUT] signoff.jsp: after new session: sessionId=A9FAEC02F8EA8CB52EB2D05EF4D8F755.srv1

       

      Have you experimented the same behavior ?

       

      From my point of view, I'm consider this behavior as a JBoss AS issue. If the user was logged on with a one-time-password (i.e. a password that can be used only once, e.g. a generated password token), the EJB access done with the cached credentials will fail because the password has already been used once.

       

      Do you think this a JBoss AS issue ?

       

      Note that the issue does not occur if the EJB security is disabled in jboss-app.xml.

       

      Thanks,

       

      Julien