6 Replies Latest reply on Jun 24, 2012 7:08 PM by cosmo

    Remeber-me not working for me in autoLogin mode

    cosmo

      Hello folks,


      I have an application that requires SEAM's remember me functionality(autoLogin), but unfortunately I can not get it to work.


      I am pretty sure the error I am making must be a minor detail I passed because all the steps in the documentation seem to be really clear.


      Anyways, thanks in advance for any time you spent in this post.



      1 Behavior expected / watched


      As cookies are being stored in my browser, I would expect that after I close the browser and re-open it again, I would be transparently logged in.
      Instead, I am taken to the log in page as if no remember me(autoLogin) functionality was enabled.



      2 Relevant source code



      components.xml


      <?xml version="1.0" encoding="UTF-8"?>
      <components xmlns="http://jboss.com/products/seam/components"
       xmlns:core="http://jboss.com/products/seam/core"
       xmlns:mail="http://jboss.com/products/seam/mail"
       xmlns:persistence="http://jboss.com/products/seam/persistence"
       xmlns:security="http://jboss.com/products/seam/security"
       xmlns:web="http://jboss.com/products/seam/web"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.2.xsd                  http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.2.xsd                  http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.2.xsd                  http://jboss.com/products/seam/bpm http://jboss.com/products/seam/bpm-2.2.xsd                  http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.2.xsd                  http://jboss.com/products/seam/mail http://jboss.com/products/seam/mail-2.2.xsd                  http://jboss.com/products/seam/web http://jboss.com/products/seam/web-2.2.xsd                  http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.2.xsd">
       <core:init debug="@debug@" jndi-pattern="@jndiPattern@" />
       <core:manager concurrent-request-timeout="500"
        conversation-id-parameter="cid" conversation-timeout="120000" parent-conversation-id-parameter="pid"/>
      
       <!-- Make sure this URL pattern is the same as that used by the Faces Servlet -->
       <web:hot-deploy-filter url-pattern="*.seam"/>
      
       <persistence:managed-persistence-context auto-create="true"
        name="entityManagerR" persistence-unit-jndi-name="java:/wmsEntityManagerFactory"/>
       <persistence:managed-persistence-context auto-create="true"
        name="entityManagerRBue" persistence-unit-jndi-name="java:/wmsRBueEntityManagerFactory"/>
       <persistence:managed-persistence-context auto-create="true"
        name="entityManagerRW" persistence-unit-jndi-name="java:/wmsRWEntityManagerFactory"/>
      
       <security:jpa-identity-store
        role-class="my.package.model.Role" user-class="my.package.model.User"/>
       <security:jpa-token-store token-class="my.package.model.AuthenticationToken"/>
       <security:identity authenticate-method="#{authenticator.authenticate}" remember-me="true"/>
       <security:remember-me mode="autoLogin"/>
      
       <event type="org.jboss.seam.security.notLoggedIn">
        <action execute="#{redirect.captureCurrentView}"/>
        <action execute="#{identity.tryLogin}"/>
       </event>
       <event type="org.jboss.seam.security.loginSuccessful">
        <action execute="#{redirect.returnToCapturedView}"/>
       </event>
      
       <factory auto-create="true" name="httpSession" value="#{facesContext.externalContext.request.session}"/>
       <factory auto-create="true" name="userIP" value="#{facesContext.externalContext.request.remoteAddr}" />
       <factory auto-create="true" name="entityManager" value="#{entityManagerRW}"/>
      </components>



      index.xhtml




      <ui:composition xmlns="http://www.w3.org/1999/xhtml"
           xmlns:s="http://jboss.com/products/seam/taglib"
           xmlns:ui="http://java.sun.com/jsf/facelets"
           xmlns:f="http://java.sun.com/jsf/core"
           xmlns:h="http://java.sun.com/jsf/html"
           xmlns:rich="http://richfaces.org/rich"
           xmlns:a4j="http://richfaces.org/a4j"
           template="layout/template.xhtml">
           <ui:define name="body">
           
           <s:div id="mainArea">
           <s:div styleClass="content_box">
           
           <rich:panel id="loginPanel"  styleClass="login-panel" width="300" height="150" >
                     
                     <f:facet name="header">Login</f:facet>     
                             
                               <h:panelGrid columns="1" columnClasses="login-table-col" style="width: 100%; text-align:center;" >
                                    <h:panelGrid columns="2" columnClasses="login-table-col2, xxx" style="margin-left:auto; margin-right:auto;">
                                         <h:outputText value="User" />
                                         <h:inputText id="usuario" value="#{credentials.username}"  style="border: 1px solid rgb(144, 144, 144); height: 19px; width: 155px;" autocomplete="off"/>
                                         <h:outputText value="Password" />
                                         <h:inputSecret id="password" value="#{credentials.password}"  style="border: 1px solid rgb(144, 144, 144); height: 19px; width: 155px;" autocomplete="off"/>
                                         <h:outputText value="Remember me" />
                                         <h:selectBooleanCheckbox value="#{rememberMe.enabled}" />                    
                                    </h:panelGrid>
                                         <h:commandButton style="login" action="#{loginForm.login}" value="Login" />
                               </h:panelGrid>
                     
               </rich:panel>
                </s:div>
                </s:div>
           
                </ui:define>
      </ui:composition>



      LoginForm.java


      @Name("loginForm")
      @Scope(ScopeType.PAGE)
      public class LoginForm {
           @In ReCaptchaProvider reCaptcha;
           @In Identity identity;
           @In BruteForceDetector bruteForceDetector;
           @In String userIP;
           
           public String login(){
                if (bruteForceDetector.needsCaptchaOnLogin(userIP)){
                     if (reCaptcha.isCaptchaValid()){
                          Contexts.getEventContext().set("comesFromCaptchaLogin", "true");
                          return identity.login();
                     }else{
                          StatusMessages.instance().addFromResourceBundle("captcha.invalid");
                          return null;
                     }
                }else{
                     return identity.login();
                }
           }     
      }



      User.java




      @Entity
      @Table(name="puser")
      public class User implements Serializable {
           private static final long serialVersionUID = 1L;
      
           private int id;
           private String password;
           private String name;
           private String email;
           private String client;
           private Set<Role> userRoles;
           
           @Id
           @GeneratedValue(strategy=GenerationType.AUTO)
           public int getId() {
                return id;
           }
      
           public void setId(int id) {
                this.id = id;
           }
      
           @UserPassword
           public String getPassword() {
                return password;
           }
      
           public void setPassword(String password) {
                this.password = password;
           }
      
           public String getName() {
                return name;
           }
      
           public void setName(String name) {
                this.name = name;
           }
      
           @UserPrincipal
           public String getEmail() {
                return email;
           }
      
           public void setEmail(String email) {
                this.email = email;
           }
      
           public String getClient() {
                return client;
           }
      
           public void setClient(String client) {
                this.client = client;
           }
           
          public void removeRole(Role role) {
              getUserRoles().remove(role);
              role.getRoleUsers().remove(this);
          }
      
          public void addRole(Role role) {
              getUserRoles().add(role);
              role.getRoleUsers().add(this);
          }
      
          @UserRoles
          @ManyToMany(targetEntity = Role.class,cascade = {CascadeType.PERSIST,CascadeType.MERGE})
          @JoinTable(name = "ex_user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
          public Set<Role> getUserRoles() {
              if (userRoles == null) {
                  userRoles = new HashSet<Role> ();
              }
              return userRoles;
          }
      
          public void setUserRoles(Set<Role> userRoles) {
              this.userRoles = userRoles;
          }
      
      }






      3 Some relevant facts




      1. Manual login is working fine

      2. No exceptions are being thrown nor messages in StatusMessage when autoLogin fails

      3. The token is being saved in DB

      4. I can see the db query each time I ask for a page that a user needs to be logged in order to see, but instead of auto login me, it takes me to login page

      5. I can see both cookies in my browser(org.jboss.seam.security.authtoken and org.jboss.seam.security.username) with values filled in even after browser close-open

      6. Username-only mode is correctly working



      4 Enviroment




      • SEAM 2.2.0 GA

      • JBoss 5.1.0 GA

      • Postgre 8.4.7

      • Open JDK 1.6.0.26

      • Ubuntu 32 bit 10.10

      • Firefox 3.6.18/Chrome 12.0.742.124




        • 1. Re: Remeber-me not working for me in autoLogin mode
          cosmo

          Ok, so to simplify a bit the problem I moved it to a project with just one data source but the results are the same as with the other project: login page is not bypassed.


          The symptoms have not changed, but while debugging a little I found 3 strange things I couldn't explain to myself. They refer to org.jboss.seam.security.RememberMe and org.jboss.seam.security.JpaTokenStore classes 


          1) Token value that is get with tokenSelector.getCookieValue(); (ln 259) is never equal to the token I see on db


          2) Even when I change the value on db during debugging and get tokenStore.validateToken(decoded.getUsername(), decoded.getValue()) to be approved (ln 266) I don't understand line 269 (credentials.setPassword(decoded.getValue());). Isn't it supposed to be filled with user's password so authenticate can be successful?
          I found that if I hardcode the password, and point 1 is valid, autologin works fine.


          3) On the other hand if I don't do this, it calls tokenStore.invalidateAll(decoded.getUsername()); (ln 274), but to my surprise, it does not delete all tokens under that username in db as ln 109-120 claim to do. It just do nothing.


          So now I am seriously thinking that I must be doing something really wrong, because as I can see that this should be working


          Did anyone have any trouble setting remember me in autologin mode?
          Thanks again for taking the time to read this lines and for any advice or suggestions

          • 2. Re: Remeber-me not working for me in autoLogin mode
            lrpieri

            Hi Aldo,

             

            Have you solved the problem? I'm at the same situation using Seam 2.2.0.GA

             

            Thanks for all

            • 3. Re: Remeber-me not working for me in autoLogin mode
              cosmo

              Hi Lelo,

              unfortunately I was not able to solve the problem, and without  support in the forums and no further info I had to rewrite the functionality myself.

              • 4. Re: Remeber-me not working for me in autoLogin mode
                lrpieri

                Thank You Aldo for your reply,

                 

                I'm also trying to rewrite the functionality overwriting the RememberMe class.

                • 5. Re: Remeber-me not working for me in autoLogin mode
                  lrpieri

                  Hi Aldo,

                  Can you tell me about your solution?

                   

                  Best regards

                  • 6. Re: Remeber-me not working for me in autoLogin mode
                    cosmo

                    Well, there are a few things that may be useful.

                    • My implementation is based on the following document "Improved Persistent Login Cookie Best Practice"
                    • Be careful with Sun JSF implementation of getting the cookie value. If found it to be broken or at least not returing the same as the sniffer said.

                              I don't know if this happens every time, but I noticed in our enviroment when returning the base 64 of "username:token:history token" a fixed byte was missing

                    • I can't remember exactly why, but there were some times when indentity.tryLogin didn't worked as expected. For that reason, I put the token verification logic within the checkIfLoggedIn method