added automated password recovery to the password reminder messages

This commit is contained in:
Eric J. Bowersox
2001-11-05 00:40:07 +00:00
parent 1c69955046
commit e201ecb34b
9 changed files with 416 additions and 9 deletions

View File

@@ -44,6 +44,9 @@ public interface VeniceEngine extends SearchMode
public abstract void sendPasswordReminder(String username)
throws DataException, AccessError, EmailException;
public abstract void completePasswordChange(int uid, int authentication)
throws DataException, AccessError, EmailException;
public abstract UserContext createNewAccount(String remote_addr, String username, String password,
String reminder) throws DataException, AccessError;

View File

@@ -31,6 +31,7 @@ import com.silverwrist.venice.htmlcheck.*;
import com.silverwrist.venice.htmlcheck.dict.*;
import com.silverwrist.venice.htmlcheck.filters.*;
import com.silverwrist.venice.security.AuditRecord;
import com.silverwrist.venice.security.PasswordGenerator;
import com.silverwrist.venice.security.PasswordHash;
import com.silverwrist.venice.security.DefaultLevels;
@@ -408,6 +409,64 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end class ConferenceCoreDataCreator
/*--------------------------------------------------------------------------------
* Internal class for password change requests
*--------------------------------------------------------------------------------
*/
class PasswordChangeRequest
{
private static final long EXPIRE_TIME = 3600000L; // one hour
private int uid; // UID of the password change request
private String username; // username of the password change request
private int authentication; // authentication value
private String email; // email address
private long timestamp; // current timestamp
PasswordChangeRequest(int uid, String username, String email)
{
this.uid = uid;
this.username = username;
this.email = email;
this.authentication = rng.nextInt(Integer.MAX_VALUE);
this.timestamp = System.currentTimeMillis();
} // end constructor
final int getUID()
{
return uid;
} // end getUID
final String getUserName()
{
return username;
} // end getUserName
final int getAuthentication()
{
return authentication;
} // end getAuthentication
final String getEmail()
{
return email;
} // end getEmail
final boolean isExpired()
{
long diff = System.currentTimeMillis() - timestamp;
return (diff>EXPIRE_TIME);
} // end isExpired
} // end class PasswordChangeRequest
/*--------------------------------------------------------------------------------
* Static data values
*--------------------------------------------------------------------------------
@@ -445,6 +504,7 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
private LinkedList cache_fp_posts = new LinkedList(); // all posts that have been published to front page
private boolean cache_fp_posts_busy = false; // busy flag for above vector
private HashSet no_compress_types = new HashSet(); // the file types that can't be compressed
private HashMap password_changes = new HashMap(); // current password change requests
/*--------------------------------------------------------------------------------
* Constructor
@@ -1025,8 +1085,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
{ // look for a user name matching this user record
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
StringBuffer sql = new StringBuffer("SELECT c.email, u.passreminder FROM users u, contacts c WHERE "
+ "u.contactid = c.contactid AND u.username = '");
StringBuffer sql = new StringBuffer("SELECT c.email, u.uid, u.passreminder FROM users u, contacts c "
+ "WHERE u.contactid = c.contactid AND u.username = '");
sql.append(SQLUtil.encodeString(username)).append("';");
ResultSet rs = stmt.executeQuery(sql.toString());
if (!(rs.next()))
@@ -1041,6 +1101,10 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
if (logger.isDebugEnabled())
logger.debug("sendPasswordReminder(\"" + username + "\") going out to \"" + email_addr + "\"");
// Enqueue a password change request.
PasswordChangeRequest pcr = new PasswordChangeRequest(rs.getInt(2),username,email_addr);
password_changes.put(new Integer(pcr.getUID()),pcr);
// Create the message to be sent.
String message = getStockMessage("reminder");
if (message==null)
@@ -1051,9 +1115,11 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end if
// Replace the message variables.
HashMap vars = new HashMap(2);
HashMap vars = new HashMap(4);
vars.put("username",username);
vars.put("reminder",rs.getString(2));
vars.put("reminder",rs.getString(3));
vars.put("change.uid",String.valueOf(pcr.getUID()));
vars.put("change.auth",String.valueOf(pcr.getAuthentication()));
message = StringUtil.replaceAllVariables(message,vars);
// Find the message subject.
@@ -1086,6 +1152,86 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end sendPasswordReminder
public void completePasswordChange(int uid, int authentication)
throws DataException, AccessError, EmailException
{
checkInitialized();
Integer key = new Integer(uid);
PasswordChangeRequest pcr;
synchronized (this)
{ // make sure we can't pull the same request out twice!
pcr = (PasswordChangeRequest)(password_changes.get(key));
if (pcr==null)
throw new AccessError("Password change request not found.");
password_changes.remove(key); // can't use the same request twice!
} // end synchronized block
if (authentication!=pcr.getAuthentication())
throw new AccessError("Invalid password change request.");
if (pcr.isExpired())
throw new AccessError("Password change request has expired.");
if (logger.isDebugEnabled())
logger.debug("completePasswordChange for user \"" + pcr.getUserName() + "\"");
// Request is valid; synthesize a new password
PasswordGenerator pgen = new PasswordGenerator();
PasswordHash phash = new PasswordHash(pgen.toString());
Connection conn = null;
try
{ // perform the database update
conn = datapool.getConnection();
Statement stmt = conn.createStatement();
StringBuffer sql = new StringBuffer("UPDATE users SET passhash = '");
sql.append(phash.toString()).append("' WHERE uid = ").append(uid).append(';');
stmt.executeUpdate(sql.toString());
} // end try
catch (SQLException e)
{ // database error - this is a DataException
logger.error("DB error resetting password for user: " + e.getMessage(),e);
throw new DataException("unable to reset password: " + e.getMessage(),e);
} // end catch
finally
{ // make sure the connection is released before we go
if (conn!=null)
datapool.releaseConnection(conn);
} // end finally
// Create the message to be sent.
String message = getStockMessage("password-change");
if (message==null)
{ // what? the message does not exist?
logger.error("\"password-change\" message does not exist in config file!");
throw new DataException("INTERNAL: password change message not specified");
} // end if
// Replace the message variables.
HashMap vars = new HashMap(2);
vars.put("username",pcr.getUserName());
vars.put("password",pgen.toString());
message = StringUtil.replaceAllVariables(message,vars);
// Find the message subject.
String subject = getStockMessage("password-change-subject");
if (subject==null)
subject = "Venice Password Changed";
// Create the emailer and send the message.
SimpleEmailer emailer = createEmailer();
emailer.setTo(pcr.getEmail());
emailer.setSubject(subject);
emailer.setText(message);
emailer.send();
if (logger.isDebugEnabled())
logger.debug("...email sent");
} // end completePasswordChange
public UserContext createNewAccount(String remote_addr, String username, String password, String reminder)
throws DataException, AccessError
{

View File

@@ -0,0 +1,103 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.servlets;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.log4j.*;
import com.silverwrist.venice.core.*;
import com.silverwrist.venice.servlets.format.*;
public class PasswordRecovery extends VeniceServlet
{
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
private static Category logger = Category.getInstance(PasswordRecovery.class);
/*--------------------------------------------------------------------------------
* Overrides from class HttpServlet
*--------------------------------------------------------------------------------
*/
public String getServletInfo()
{
String rc = "PasswordRecovery servlet - Chnages passwords for users that forgot them\n"
+ "Part of the Venice Web Communities System\n";
return rc;
} // end getServletInfo
/*--------------------------------------------------------------------------------
* Overrides from class VeniceServlet
*--------------------------------------------------------------------------------
*/
protected VeniceContent doVeniceGet(HttpServletRequest request, VeniceEngine engine,
UserContext user, RenderData rdat)
throws ServletException, IOException, VeniceServletResult
{
int uid, auth;
try
{ // retrieve UID and authentication strings from URL
String foo = request.getPathInfo().substring(1);
int n = foo.indexOf('.');
if (n<0)
return new ErrorBox(null,"Invalid parameters to password recovery.","top");
uid = Integer.parseInt(foo.substring(0,n));
auth = Integer.parseInt(foo.substring(n+1));
} // end try
catch (NumberFormatException nfe)
{ // invalid parameters passed...
return new ErrorBox(null,"Invalid parameters to password recovery.","top");
} // end catch
try
{ // complete the password change
engine.completePasswordChange(uid,auth);
// now return a "password changed" page
changeMenuTop(request);
setMyLocation(request,"top"); // lie so that we get the "Log In" link up top
return new PasswordChanged();
} // end try
catch (DataException de)
{ // there was a database error changing your password
return new ErrorBox("Database Error","Database error changing password: " + de.getMessage(),"top");
} // end catch
catch (AccessError ae)
{ // this indicates a problem with the request ID or authentication
return new ErrorBox("Invalid Request",ae.getMessage(),"top");
} // end catch
catch (EmailException ee)
{ // error sending the confirmation email
return new ErrorBox("E-mail Error","E-mail error sending update: " + ee.getMessage(),"top");
} // end catch
} // end doVeniceGet
} // end class PasswordRecovery

View File

@@ -0,0 +1,87 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
*
* Contributor(s):
*/
package com.silverwrist.venice.servlets.format;
import javax.servlet.ServletRequest;
import com.silverwrist.venice.core.SIGContext;
public class PasswordChanged implements JSPRender
{
/*--------------------------------------------------------------------------------
* Static data members
*--------------------------------------------------------------------------------
*/
// Attribute name for request attribute
protected static final String ATTR_NAME = "com.silverwrist.venice.content.PasswordChanged";
/*--------------------------------------------------------------------------------
* Constructor
*--------------------------------------------------------------------------------
*/
public PasswordChanged()
{ // do nothing
} // end constructor
/*--------------------------------------------------------------------------------
* External static functions
*--------------------------------------------------------------------------------
*/
public static PasswordChanged retrieve(ServletRequest request)
{
return (PasswordChanged)(request.getAttribute(ATTR_NAME));
} // end retrieve
/*--------------------------------------------------------------------------------
* Implementations from interface VeniceContent
*--------------------------------------------------------------------------------
*/
public String getPageTitle(RenderData rdat)
{
return "Your Password Has been Changed";
} // end getPageTitle
public String getPageQID()
{
return null;
} // end getPageQID
/*--------------------------------------------------------------------------------
* Implementations from interface JSPRender
*--------------------------------------------------------------------------------
*/
public void store(ServletRequest request)
{
request.setAttribute(ATTR_NAME,this);
} // end store
public String getTargetJSPName()
{
return "password_changed.jsp";
} // end getTargetJSPName
} // end class PasswordChanged

View File

@@ -7,7 +7,7 @@
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is the Venice Web Community System.
* The Original Code is the Venice Web Communities System.
*
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are