Recipe11.5.Implementing


Recipe 11.5. Implementing "Remember Me" Logins

Problem

You want to provide a "remember me" feature so a user's username and password are prefilled on the logon form if that user has logged on before.

Solution

In your Action that logs a user in, create persistent cookies containing the user's base-64 encoded username and password. The private saveCookies( ) and removeCookies( ) methods shown in Example 11-8 manipulate the cookies as needed.

Example 11-8. An Action that stores or removes cookies
package com.oreilly.strutsckbk.ch11; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.beanutils.PropertyUtils; import org.apache.struts.action.Action; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import com.oreilly.servlet.Base64Encoder; public final class MyLogonAction extends Action {     public ActionForward execute( ActionMapping mapping,                                    ActionForm form,                                   HttpServletRequest request,                                    HttpServletResponse response)              throws Exception {         HttpSession session = request.getSession( );         ActionErrors errors = new ActionErrors( );         String username = (String) PropertyUtils.getSimpleProperty(form,                                     "username");         String password = (String) PropertyUtils.getSimpleProperty(form,                                     "password");         boolean rememberMe = ((Boolean) PropertyUtils.getSimpleProperty(                                    form, "rememberMe")).booleanValue( );         // Call your security service here         //SecurityService.authenticate(username, password);         if (rememberMe) {             saveCookies(response, username, password);         } else {             removeCookies(response);         }                  session.setAttribute("username", username);         return mapping.findForward("success");     }          private void saveCookies(HttpServletResponse response, String                               username, String password) {         Cookie usernameCookie = new Cookie("StrutsCookbookUsername",                                            Base64Encoder.encode(username));         usernameCookie.setMaxAge(60 * 60 * 24 * 30); // 30 day expiration         response.addCookie(usernameCookie);         Cookie passwordCookie = new Cookie("StrutsCookbookPassword",                                            Base64Encoder.encode(password));         passwordCookie.setMaxAge(60 * 60 * 24 * 30); // 30 day expiration         response.addCookie(passwordCookie);     }     private void removeCookies(HttpServletResponse response) {         // expire the username cookie by setting maxAge to 0         // (actual cookie value is irrelevant)         Cookie unameCookie = new Cookie("StrutsCookbookUsername", "expired");         unameCookie.setMaxAge(0);         response.addCookie(unameCookie);         // expire the password cookie by setting maxAge to 0         // (actual cookie value is irrelevant)         Cookie pwdCookie = new Cookie("StrutsCookbookPassword", "expired");         pwdCookie.setMaxAge(0);         response.addCookie(pwdCookie);     } }

When a user goes to the logon page, fill the username and password fields with values from the cookie, decoded from base-64, using the Struts bean:cookie tag, as shown in Example 11-9.

Example 11-9. Setting logon form field values from cookies
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="com.oreilly.servlet.*" %> <%@ taglib uri="/tags/struts-bean" prefix="bean" %> <%@ taglib uri="/tags/struts-html" prefix="html" %> <html> <head> <title>Struts Cookbook - Cookie Logon</title> </head> <body> <html:errors/> <html:form action="/SubmitCookieLogon" focus="username">   <bean:cookie  name="StrutsCookbookUsername" value=""/>   <bean:cookie  name="StrutsCookbookPassword" value=""/>   <table border="0" width="100%">   <tr>     <th align="right">       <bean:message key="prompt.username"/>:     </th>     <td align="left">       <html:text property="username" size="16" maxlength="18"           value="<%=Base64Decoder.decode(uname.getValue( ))%>"/>     </td>   </tr>   <tr>     <th align="right">       <bean:message key="prompt.password" bundle="alternate"/>:     </th>     <td align="left">       <html:password property="password" size="16" maxlength="18"                     redisplay="false"      </td>   </tr>   <tr>     <th align="right">       <bean:message key="prompt.rememberMe"/>:     </th>     <td align="left">       <html:checkbox property="rememberMe"/>     </td>   </tr>   <tr>     <td align="right">       <html:submit property="Submit" value="Submit"/>     </td>     <td align="left">       <html:reset/>     </td>   </tr> </table> </html:form> </body> </html>

Discussion

A cookie consists of a name-value data pair that can be sent to a client's browser and then read back again at a later time. Browsers provide security for cookies so a cookie can only be read by the server that originally created it. Cookies must have an expiration period.

Though cookies are in widespread use and are supported by modern browsers, they do pose a privacy risk. Most browsers allow the user to disable them. You can design your web application to use cookies to improve the user experience, but you shouldn't require users to use cookies.


The logon Action of Example 11-8 retrieves the username and password from the logon form. This form includes the true/false property rememberme, which indicates if the users want their login credentials remembered. If users want to be remembered, they check the checkbox for the rememberme property. In the MyLogonActionif rememberme is truethe cookies are created and saved in the response. If rememberme is false, the cookies for username and password have their maxAge set to 0, effectively removing them from the response.

The bean:cookie tags used in Example 11-9 retrieve the cookie values from the request and store them in scripting variables. These tags specify the empty string ("") as the default value in case cookies are disabled. The initial values for the login form fields are set to the values from the scripting variables.

The Solution shown here does not address cookie security issues. For a production system, the data sent in the cookies should be encrypted. A simple encryption scheme, such as MD5 or a variant of the Secure Hash Algorithm (SHA), can be used to encrypt the cookie value when it is created. Since the server creates the cookie and is the only party that can legitimately use the data, it can encrypt and decrypt the data using the algorithm of its own choosing. Alternatively, you can send the cookies only over HTTPS, thereby providing encryption/decryption at the transport level.

See Also

You can use cookies to log in a user automatically; in other words, if users have a cookie(s) with valid credentials for the web application they don't have to submit the login form at all. The automatic login approach is shown in Recipe 11.7.

Recipe 11.10 shows how to use the open source SecurityFilter software to implement "remember me" functionality. Its implementation includes support for cookie encryption and other settings.

Java Servlet Programming by Jason Hunter (O'Reilly) covers servlet development from top to bottom, including the Cookie APIs. The Base64 encoder and decoder used in this recipe are part of the companion com.oreilly.servlet classes available from http://www.servlets.com/cos/.

The foundation of Java server-side cookie handling is the Servlet Specification and API, available for download from http://java.sun.com/products/servlet/download.html.

The JavaBoutique has a nice tutorial on server-side cookie handling found at http://javaboutique.internet.com/tutorials/JSP/part09/. Alexander Prohorenko has written a good article on cookie security issues for O'Reilly's ONLamp.com site at http://www.onlamp.com/pub/a/security/2004/04/01/cookie_vulnerabilities.html.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net