20030114 Tuesday January 14, 2003

Simple Intentions turn into Remember Me Login I woke up this morning, and had the simple intention of blogging about one of my favorite tools, The Color Schemer. If you're a wanna-be designer like me, it's awesome. It helps you match "like" colors and also allows you to select any color on your screen. It's one of my most invaluable web design tools. Putting a tip about this was my only hope at 4:30 when I sat down at this computer. Now it's 5:39.

Why am I still here? I got caught up in reading the Colorado Bloggers mailing list - which actually got some traffic yesterday. This is one of the first times I've received a message from the list. One of the members pointed me to a another Photo Album for the web. It's called Gallery and she has an example setup. Looks like it runs on PHP. Well that shouldn't have taken me an hour, right?

The activity that's filled my last hour has been wrestling with Erik Hatcher's request for "remember me" functionality in a J2EE app, using container-managed security. The good news is that I did get it working - here's how:

  1. First, I added a checkbox called "rememberMe" to my login.jsp. When the user clicks "submit", I do some JavaScript logic. This logic entails saving the username and password as cookies - but only if the rememberMe checkbox is checked. If rememberMe is checked, a cookie is set called "rememberMe" with a value of "true."
  2. Using Roller's BreadCrumbFiler (maps to /*), I added some logic to check for the existence of the "rememberMe" cookie, and if it exists, to route the user to "j_security_check?j_username="+usernameCookie+"&j_password="+passwordCookie.

This all worked fine and dandy right off the bat - took me about 10 minutes to implement. The problem was that a user couldn't "logout." So I've spent the last hour (now it's been an hour and 1/2) with my own ignorance trying to delete cookies (and doing null checks and such) so users could logout. And I just got it working - fricken sweet! What a way to start the day! The only problem I could see now is if a user tries a username/password and selects "remember me", but then closes their browser. The BreadCrumbFilter will keep trying to authenticate them - yep, I just verified that that's a problem. It's also a problem when they enter an invalid password and select rememberMe.

One way to solve this is to not set the "rememberMe" and "password" cookies until someone has successfully authenticated. Maybe I could use the breadcrumbs in the BreadCrumbFilter to check the last URL accessed, and if it's already j_security_check, don't do the routing. Anyway, here's the code that does the heavy lifting in BreadCrumbFilter:

Cookie rememberMe = RequestUtil.getCookie(request, "rememberMe");
// check to see if the user is logging out, if so, remove the
// rememberMe cookie and password Cookie
if (request.getRequestURL().indexOf("logout") != -1 && 
	(rememberMe != null)) {
    if (log.isDebugEnabled()) {
        log.debug("deleting rememberMe-related cookies");
    }

    response =
        RequestUtil.deleteCookie(response,
                                 RequestUtil.getCookie(request,
                                                       "rememberMe"));
    response =
        RequestUtil.deleteCookie(response,
                                 RequestUtil.getCookie(request,
                                                       "password"));
}

if (request.getRequestURL().indexOf("login") != -1) {
    // container is routing user to login page, check for remember me cookie
    Cookie username = RequestUtil.getCookie(request, "username");
    Cookie password = RequestUtil.getCookie(request, "password");

    if ((rememberMe != null) && (password != null)) {
        // authenticate user without displaying login page
        String route =
            "j_security_check?j_username=" +
            RequestUtils.encodeURL(username.getValue()) +
            "&j_password=" +
            RequestUtils.encodeURL(password.getValue());

        if (log.isDebugEnabled()) {
            log.debug("I remember you '" + username.getValue() +
                      "', authenticating...");
        }

        response.sendRedirect(response.encodeRedirectURL(route));

        return;
    }
}

I can post the code for RequestUtil if you need it. The class RequestUtils (for encoding URLs) is a Struts class. Posted in Java at Jan 14 2003, 06:07:21 AM MST 4 Comments

Comments:

Matt - nice work! Which application server are you using? Tomcat? Does it do a server-side forward or redirect to the login page? And then how does it take you to the page you originally requested? JBoss does a redirect in both cases, which means you lose the request parameters and a Filter wouldn't catch them. Unless I'm missing something obvious.

Posted by Erik Hatcher on January 14, 2003 at 06:48 AM MST #

also, does redirecting to j_security_check work in other application servers? I don't believe that is going to work across vendors, because the spec says that the user must go to a protected resource first, and if you redirect directly to j_security_check then things might not work. this is just a hunch. keep me posted on your progress with this! i'm eagerly tuning in....

Posted by Erik Hatcher on January 14, 2003 at 06:51 AM MST #

To answer your first question: I am using Tomcat - and I've only tested this on WinXP, Win2K and Tomcat 4.1.18. Tomcat seems to do a redirect, as login.jsp shows up in the address bar. It just *knows* the page I originally requested, I'm not able to retrieve this value in any way. I'm not relying in any request parameters to make this happen, so redirects don't affect me. One thing I am doing on authentication is I have my login form mapped to "/auth/" rather than j_security_check. I have a servlet mapped to "auth" that does SSL redirect/password encryption - but it eventually redirects to j_security_check. I don't know that redirecting to j_security_check will work in all app servers - try it! It should - one way to verify is to check your login form's "action" value to see if it's still "j_security_check" when your login.jsp loads. I know that iPlanet used to replace "j_security_check" with it's own value. In order to workaround my bad password problem - I ended up creating another cookie called "authenticated" that only gets set in my ActionFilter. ActionFilter is mapped to the same URL as my protected resources. Then in BreadCrumbFilter, I ensure that the following cookies are set: rememberMe, password, authenticated. All this seems to be working pretty well for me. I'm lucky in that I only need to support Tomcat in the current projects I'm on.

Posted by Matt Raible on January 14, 2003 at 08:10 AM MST #

response.sendRedirect(response.encodeRedirectURL(route)); is really not a good idea, you are sending the password in the URL better would be to use forward of the servlet container instead

Posted by peter on February 21, 2003 at 12:40 PM MST #

Post a Comment:
  • HTML Syntax: Allowed
Click me to subscribe
Matt Raible is the Lead UI Architect at LinkedIn. The opinions on this site are mine, not my employers.
« November 2008
SunMonTueWedThuFriSat
      
1
2
3
6
7
8
9
10
11
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
      
Today

Recent Entries

Tag Cloud