Handling Forgotten Passwords

I l @ ve RuBoard

Humans are a forgetful species. Many of us consider ourselves lucky if we can remember our children's names , much less a password we selected for a site that we visited six months ago.

Any good e-commerce site will include a way to retrieve a forgotten password. Some have opted for questions, such as "What's your favorite animal?" to serve as a secondary question that you can answer to reset or be reminded of your password. The problem with that approach is that the user could very well forget what the answer to the second question is as well.

The gold standard for lost passwords is to e-mail the password to the address of record for the account. The theory is, if a user has lost control of his e-mail account, he has bigger problems to worry about than someone gaining access to his store registration.

To implement this, you need to be able to send a piece of e-mail from Java. Thankfully, Tomcat 4 includes built-in support for sending e-mail. All you have to do is configure it. Note that this requires the JavaMail and JavaBean Activation Framework libraries, both of which are available from Sun and are included in the extras directory in the zip file available on the Sams Web site.

To configure e-mail support, you need to add some text to the web.xml that you created for the bfg example application (see Listing 8.10).

Listing 8.10 web.xml Revised
 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"     "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">     <web-app>   <servlet>     <servlet-name>log4j-init</servlet-name>     <servlet-class>com.bfg.services.Log4jInit</servlet-class>     <init-param>       <param-name>log4j-init-file</param-name>       <param-value>WEB-INF/log4j.properties</param-value>     </init-param>     <load-on-startup>1</load-on-startup>   </servlet>   <servlet>     <servlet-name>turbine-init</servlet-name>     <servlet-class>com.bfg.services.TurbineInit</servlet-class>     <init-param>       <param-name>turbine-resource-directory</param-name>       <param-value>c:/tomcat/webapps/bfg/WEB-INF</param-value>     </init-param>     <load-on-startup>1</load-on-startup>   </servlet>    <session-config>      <session-timeout>5</session-timeout>     </session-config>     <resource-ref>       <res-ref-name>mail/session</res-ref-name>       <res-type>javax.mail.Session</res-type>       <res-auth>Container</res-auth>     </resource-ref> 

The addition of the resource-ref lines is absolutely boilerplate ; it doesn't change from application to application.

Next, you need to specify a valid SMTP host in your Tomcat server.xml file. When you first created the entry for the bfg application, you just copied the examples context entry that comes with Tomcat. That example sets the SMTP host to localhost, which works only if you're running an SMTP server on your local machine. This might be the case if you're using Linux, but it almost certainly is not the case on a Windows machine. Listing 8.12 shows a revised entry for your application in server.xml.

Listing 8.12 The BFG Entry in server.xml
 <!-- BFG Context --> <Context path="/bfg" docBase="bfg" debug="0"          reloadable="true">   <Environment name="maxExemptions" type="java.lang.Integer"               value="15"/>   <Parameter name="context.param.name" value="context.param.value"              override="false"/>   <Resource name="mail/session" auth="CONTAINER"             type="javax.mail.Session"/>   <ResourceParams name="mail/session">     <parameter>       <name>mail.smtp.host</name>       <value>localhost</value>     </parameter>   </ResourceParams> </Context> 

The relevant lines in the server.xml file are these:

 <name>mail.smtp.host</name> <value>localhost</value> 

Under the bfg context, change localhost to the address of your SMTP server ”either yours or the one that your ISP has you use.

Now that Java e-mail has been configured, you can add the appropriate functionality to the Customer class (see Listing 8.13).

Listing 8.13 Additions to Customer.java for E-mail
 import javax.naming.NamingException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingEnumeration; import javax.naming.directory.InitialDirContext; import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.AddressException; . . .     private static ResourceBundle email_bundle =       ResourceBundle.getBundle("com.bfg.emailProperties"); . . .     public void sendPasswordReminder()       throws NamingException, AddressException, MessagingException {       Context initCtx = new InitialContext();       Context envCtx = (Context)initCtx.lookup("java:comp/env");       Session session = (Session) envCtx.lookup("mail/session");       Message message = new MimeMessage(session);       message.setFrom(new InternetAddress(email_bundle.getString("fromAddr")));       InternetAddress to[] = new InternetAddress[1];       to[0] = new InternetAddress(email);       message.setRecipients(Message.RecipientType.TO, to);       message.setSubject(email_bundle.getString("lostSubj"));       message.setContent(email_bundle.getString("lostContent") + password,                    "text/plain");       Transport.send(message);     } 

After importing a number of new required classes needed for support of naming and e-mail, you define another resource bundle so that you can put things such as the sender's e-mail address and the text of the message into a property file rather than hard-wiring it in the Java code. This is the same philosophy that you adopted with the SQL query strings. Listing 8.14 shows the contents of this file.

Listing 8.14 emailProperties.properties
 #fromAddr=customerservice@bfgbooks.com fromAddr=turner@blackbear.com lostSubj=Lost Password Reminder lostContent=Someone has sent a request for a password reminder using your\n\ e-Mail address.  If this person was not you, please contact us immediately\n\ so that we can address the situation.  If it was you, your password is\n\ included at the bottom of this message.\n\ \n\ Thank you,\n\ Books for Geeks Customer Service\n\ customerservice@bfgbooks.com\n\ \n\ PASSWORD= 

Note that you probably won't be able to use the fake customer service address as the fromAddr field because most SMTP relay servers will bounce it as bogus . This is also true when developing a real application for which the domain name is not registered yet. For that reason, it has been commented out and a test address has been put in its place.

The Java Naming and Directory Interface (JNDI) is used to get a handle on the persistent mail session object that you defined for the application. The application gets a new MimeMessage; sets the addresses, subject, and content; and then sends the message.

With the back-end code written, all that's left is to write the JSP. An interesting security question to consider is this: Should you have a different message displayed if the user types in an e-mail address that isn't associated with a registered user? It can be argued that if you do this, it provides a way for a hacker to find out whether an e-mail address is valid so that he can try to guess the password; under that logic, you should display a generic "We'll send you your password if we find it" message, even if no such address really exists in your records.

The counter argument to that argument, in this case, is that the e-mail address is used as the customer's primary login key. All a hacker would need to do is to try to create a new account using that e-mail address and get the duplicate address message to know that the account was ripe for attack. In other words, there's no harm in letting a customer know that he didn't use the right address.

Listing 8.15 shows the JSP for implementing lost password.

Listing 8.15 lostPassword.jsp
 <%@ page import="com.bfg.customer.Customer" %> <%     String email = request.getParameter("email"); boolean not_found = false;     if (email == null) {      email = "";     } if (request.getParameter("SUBMITTED") != null) {     Customer c = Customer.findCustomer(email);     if (c != null) {       c.sendPasswordReminder();       response.sendRedirect("sendPassword.jsp");     }     not_found = true; } %> <HEAD><TITLE>Lost Password Retrieval</TITLE></HEAD><BODY> Please enter the e-Mail address you used to register your account. <FORM METHOD=POST ACTION="lostPassword.jsp"> <INPUT TYPE="HIDDEN" NAME="SUBMITTED" VALUE="T"> <% if (not_found) { %> <FONT COLOR="#FF0000">Address not found in customer records.</FONT><BR> <% } %> e-Mail Address: <INPUT NAME="email" TYPE="TEXT" SIZE=50        VALUE="<%= email %>"><BR> <INPUT TYPE=SUBMIT> </FORM> </BODY> 

Again, the "redirect on success" trick is used to keep the user on the same page if the e-mail address isn't found. The sendPassword.jsp page is a simple static page telling the user that the password has been sent. See Figures 8.3 and 8.4.

Figure 8.3. Lost password page.

graphics/08fig03.jpg

Figure 8.4. Lost password result.

graphics/08fig04.jpg

If everything has been set up right and you specified an e-mail address that is actually your own, you will get a piece of e-mail that looks like this:

 From: turner@blackbear.com Sent: Sunday, October 14, 2001 11:59 AM To: turner@blackbear.com Subject: Lost Password Reminder Someone has sent a request for a password reminder using your e-Mail address.  If this person was not you, please contact us immediately so that we can address the situation.  If it was you, your password is included at the bottom of this message. Thank you, Books for Geeks Customer Service customerservice@bfgbooks.com PASSWORD=apassword 
I l @ ve RuBoard


MySQL and JSP Web Applications. Data-Driven Programming Using Tomcat and MySQL
MySQL and JSP Web Applications: Data-Driven Programming Using Tomcat and MySQL
ISBN: 0672323095
EAN: 2147483647
Year: 2002
Pages: 203
Authors: James Turner

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