0

I am studying the following to implement 'Remember me" functionality : http://varuntayur.wordpress.com/2012/01/25/session-management-in-gwt/

I have most of it working however, and my apologies this is probably very basic, I am having difficulty returning the session ID to the client side.

My server side code is:

The call to the DB to verify user and return details:

public Account authenticateAccount(String accountName, String pass) {

        Account account = null; // necessary unless you do something in the exception handler
        String stored_hash = null;
        PreparedStatement ps = null;

        // Create connection/statement variables outside of try block
        Connection c = null;

        String selectQry = ("SELECT acc_id, grp_id, acc_password, acc_level, acc_enabled, acc_archived " +
                            "FROM at_accounts " +
                            "WHERE acc_email_address = ?;");

        try {
            // Get Connection and Statement from DataSource
            c = ds.getConnection();
            ps = c.prepareStatement(selectQry);

            try {
                // Create a statement and execute the query on it           
                ps.setString(1, accountName);

                // Get result set
                ResultSet result = ps.executeQuery();

                while (result.next()) {
                    account = new Account(result.getString(1), result.getString(2), null, result.getString(3), 
                    result.getString(4), null, result.getInt(5), result.getDate(6), null);

                    stored_hash = result.getString(3);
                }

                // Clean up
                ps.close();
                c.close();

            } catch (SQLException se) {
                System.out.println("SQLException occurred in authenticateAccount: " + se.toString());
            } catch (Exception e) {
                System.out.println("Errors occurred in authenticateAccount: " + e.toString());
            }


        } catch (SQLException e1) {
            System.out.println("SQLException occurred in authenticateAccount: " + e1.toString());
            e1.printStackTrace();
        } finally {

            // Ensure connection is closed and returned to the pool, even if errors occur.
            // This is *very* important if using a connection pool, because after all the
            // connections are used, the application will hang on getConnection(), waiting
            // for a connection to become available.
            // Any errors from the following closes are just ignored.  The main thing is
            // that we have definitely closed the connection.
            try { if(ps != null) ps.close(); } catch (Exception e) {}
            try { if(c != null) c.close(); } catch (Exception e) {}
        }
        // Done

        //Check that the hashed value of the password equals the stored hashed value
        //If it does not then account will be set to null.
        if (stored_hash != null) {
            if (BCrypt.checkpw(pass, stored_hash))  {
            } else {
                account = null;
            }
        } else {
            account = null;
        }

        storeUserInSession(account);
        return account;
    }

The code to store the session ID

private void storeUserInSession(Account account)
{
    HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
    HttpSession session = httpServletRequest.getSession(true);
    session.setAttribute("account", account);
    System.out.println("storeUserInSession: " + account);
}

The println returns: "storeUserInSession: org.AwardTracker.client.Account@2eca7997".

When this is returned to the client side I use the following code to retrieve the session ID and create the cookie:

//Remember the Login
String sessionID =  account.getSessionId();
Window.alert("Session ID = " + sessionID);
final long DURATION = 1000 * 60 * 60 * 24 * 14; //duration remembering login. 2 weeks in this example.
Date expires = new Date(System.currentTimeMillis() + DURATION);
Cookies.setCookie("sid", sessionID, expires, null, "/", false);

The Window.alert shows account.getSessionId() to be null (all other account information is returned correctly, e.g., access level (user, admin, etc)).

Thanks for any assistance.

Regards,

Glyn

Glyn
  • 1,933
  • 5
  • 37
  • 60

1 Answers1

0

The problem is that you never set the sessionID in the account Object, so it's always null

EDIT: moved storeUserInSession to the if-clause, so its only stored if the accountdata is valid
To do this you could do something like this:

public Account authenticateAccount(String accountName, String pass) {
    //....Code...
    if (stored_hash != null) {
        if (BCrypt.checkpw(pass, stored_hash))  {
       //Before returning the account you have to set the sessionID for the account 
            account = storeUserInSession(account);
        } else {
            account = null;
        }
    } else {
        account = null;
    }
    return account;
}

then change returntype of storeUserInSession(account) to account and set the sessionID there

private Account storeUserInSession(Account account)
{
    HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
    HttpSession session = httpServletRequest.getSession(true);
    //here you store the sessionID in account
    account.setSessionId(session.getId());
    session.setAttribute("account", account);
    return account;
}

EDIT: An explanation how login works here:

  1. On login check if the userdata is valid.
    You do this in authenticateAccount()
  2. If the login is valid you create a new session for this User and add the accountData to this session
    HttpSession session = httpServletRequest.getSession(true)
    session.setAttribute("account", account);
  3. On client side you add a cookie that is valid until a certain date, then forward the user to your protected page.
    Cookies.setCookie("sid", sessionID, expires)
  4. When the user returns to your page you check if there is cookie with the name "sid". Keep in mind that this is not the validation of the user, thats done later on serverside. Here is just checked if the user was logged in before.

     public void onModuleLoad()
     {   //user was logged in before?(the Stringname "sessionID" is a little bit irritating here
    String sessionID = Cookies.getCookie("sid");
    //no? then just show the loginWindow
    if (sessionID == null)
    {
        displayLoginWindow();
    } else
    {   //yes?then check if there is a valid session for him 
        checkWithServerIfSessionIdIsStillLegal();
    }
    

    }

  5. On serverside you check now if the session is still valid. You can do that WITHOUT storing any sessionID in the cookie because you get the actual session with HttpSession session = httpServletRequest.getSession(). The point here is that you dont check if the sessionID is matching but if there is stored any account in this session(Look at point 2). If not then its obviously not the same session where you stored the accountdata and the user has to login again.

     Object accountObj = session.getAttribute("account");
             if (accountObj != null && accountObj instanceof Account)
             {
                  account = (Account) accountObj;
             }`
    

I hope this makes everthing a little bit more clear and shows that you dont have to store the sessionID in the cookie.

Tobika
  • 1,037
  • 1
  • 9
  • 18
  • Hi @Tobika, I made this change and the "String sessionID = account.getSessionId();" is still returning null. It seems to me that I should be calling "storeUserInSession(account);" before I load the account details in the while loop so I can return it with the other details. However, then I would need to call "storeUserInSession" with a string (i.e., accountName). Would this be valid? Thanks for your help. Regards, Glyn – Glyn Dec 10 '14 at 00:17
  • Hi @Tobika, I tried this with "sessionID = storeUserInSession(accountName);" before the try statement and including "sessionID" in place of the last "null" (i.e., account = new Account(result.getString(1), result.getString(2), null, result.getString(3), result.getString(4), null, result.getInt(5), result.getDate(6), sessionID);). However, this just returns the account name to the client side which does not seem terribly secure to me. Is this how it is supposed to work? If it is then is there a better way to do this? Regards, Glyn – Glyn Dec 10 '14 at 00:51
  • @Glyn hey, i edited my post to explain the login a little better...i hope that helps – Tobika Dec 10 '14 at 08:57
  • and to answer your first comment. yes it would be valid to just store the accountname since it just checked if SOMETHING is stored, and not the whole account data. it would be just faster when all the account information would be stored so you dont have to call the databank for this – Tobika Dec 10 '14 at 11:00
  • Hi @Tobika, sorry for the delay in responding, I did not get a notification of your response and I have been busy with a date issue. This concerns me. If I only have a low level access and edit the cookie so that it has the user name of an administrator then the application checks if the administrator has logged in within the last 'valid time frame' and if they have goes to the first view and I have administrator access. Is that correct? Thank you very much for your help. Regards, Glyn – Glyn Dec 15 '14 at 04:19
  • hey @Glyn, no, you would not have admin access, because all this important accountinformation is stored on erverside with session.setAttribute("account", account);. The only possibility to get adminaccess is to change the JSESSIONID Cookie to a sessionID of an admin that has is logged in. if you want to understand the httpSession better i recommend you to read [this short explanation](http://stackoverflow.com/a/1701107/2894562) or [this tutorial](http://www.journaldev.com/1907/java-servlet-session-management-tutorial-with-examples-of-cookies-httpsession-and-url-rewriting#servlet-httpsession) – Tobika Dec 15 '14 at 12:41
  • @Glyn ive pasted [some example code here](http://pastie.org/private/qfzfqae8k78id1vkcq56g) thats how i did it some time ago...hope this is more understandable than the tutorial – Tobika Dec 15 '14 at 14:27
  • Thanks @Tobika, I really appreciate your help. It may take me a while to study this as this is not my day job and I am wrestling with a date issue at the moment. Regards, Glyn – Glyn Dec 16 '14 at 00:57