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

@ -125,7 +125,15 @@ Here is the password reminder for your account "${username}" as you requested:
${reminder} ${reminder}
If this reminder is not sufficient for you to remember what your password is, If this reminder is not sufficient for you to remember what your password is,
please contact the server administrator for further assistance. then the system can change your password for you. To do so, please visit the following URL:
http://delenn/venice/passrecovery/${change.uid}.${change.auth}
Your password will be changed and a new password will be E-mailed to you at this address.
If you did NOT request a password reminder, then this message was sent by someone
attempting to access your account without your knowledge. Do not panic! Nothing has
happened to your account or password yet, but please do notify the system administrator.
-- The Management -- The Management
]]> ]]>
@ -133,6 +141,22 @@ please contact the server administrator for further assistance.
<reminder-subject>Venice Password Reminder Message</reminder-subject> <reminder-subject>Venice Password Reminder Message</reminder-subject>
<password-change>
<![CDATA[
The password for your account "${username}" has been changed. The new password is "${password}".
You should log into Venice immediately and change the password to something else. You can change the
password for your account, once you are logged in, by clicking on the "Profile" link in the top bar.
If you did NOT request a password change on your account, please notify the system administrator
IMMEDIATELY.
-- The Management
]]>
</password-change>
<password-change-subject>Venice Password Changed</password-change-subject>
<!-- Invitation message to a public SIG --> <!-- Invitation message to a public SIG -->
<!-- Parameters: signame = name of SIG, sigalias = alias of SIG, personal = personal message, <!-- Parameters: signame = name of SIG, sigalias = alias of SIG, personal = personal message,
fullname = name of inviter, username = user name of inviter --> fullname = name of inviter, username = user name of inviter -->
@ -140,7 +164,7 @@ please contact the server administrator for further assistance.
<![CDATA[ <![CDATA[
Hi! I would like to invite you to join the "${signame}" Special Interest Group (SIG) on the Venice Hi! I would like to invite you to join the "${signame}" Special Interest Group (SIG) on the Venice
conferencing system. To do so, you must register as a user, which is absolutely free! Just point conferencing system. To do so, you must register as a user, which is absolutely free! Just point
your Web browser at <http://delenn:8080/venice/sig/${sigalias}> and click the "Create Account" link your Web browser at <http://delenn/venice/sig/${sigalias}> and click the "Create Account" link
at the top of the page, or click the "Log In" link if you already have a Venice account. Once you have at the top of the page, or click the "Log In" link if you already have a Venice account. Once you have
completed the process, click the "Join Now" button. You will then be able to take part in the conferences completed the process, click the "Join Now" button. You will then be able to take part in the conferences
that are going on in the SIG. that are going on in the SIG.
@ -161,7 +185,7 @@ Hope to see you in "${signame}" soon!
<![CDATA[ <![CDATA[
Hi! I would like to invite you to join the "${signame}" Special Interest Group (SIG) on the Venice Hi! I would like to invite you to join the "${signame}" Special Interest Group (SIG) on the Venice
conferencing system. To do so, you must register as a user, which is absolutely free! Just point conferencing system. To do so, you must register as a user, which is absolutely free! Just point
your Web browser at <http://delenn:8080/venice/sig/${sigalias}> and click the "Create Account" link your Web browser at <http://delenn/venice/sig/${sigalias}> and click the "Create Account" link
at the top of the page, or click the "Log In" link if you already have a Venice account. Once you have at the top of the page, or click the "Log In" link if you already have a Venice account. Once you have
completed the process, click the "Join Now" button. You will be prompted for the "password" for this completed the process, click the "Join Now" button. You will be prompted for the "password" for this
SIG, which is "${joinkey}". You will then be able to take part in the conferences that are going on in the SIG, which is "${joinkey}". You will then be able to take part in the conferences that are going on in the

View File

@ -230,6 +230,14 @@
<servlet-class>com.silverwrist.venice.servlets.StyleSheet</servlet-class> <servlet-class>com.silverwrist.venice.servlets.StyleSheet</servlet-class>
</servlet> </servlet>
<servlet>
<servlet-name>passrecovery</servlet-name>
<description>
Performs a password change operation for a user that's forgotten their password.
</description>
<servlet-class>com.silverwrist.venice.servlets.PasswordRecovery</servlet-class>
</servlet>
<!-- the following are test servlets, they should go away --> <!-- the following are test servlets, they should go away -->
<servlet> <servlet>
@ -348,6 +356,11 @@
<url-pattern>/stylesheet</url-pattern> <url-pattern>/stylesheet</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet-mapping>
<servlet-name>passrecovery</servlet-name>
<url-pattern>/passrecovery/*</url-pattern>
</servlet-mapping>
<!-- the following are test servlets, they should go away --> <!-- the following are test servlets, they should go away -->
<servlet-mapping> <servlet-mapping>
<servlet-name>testformdata</servlet-name> <servlet-name>testformdata</servlet-name>

View File

@ -44,6 +44,9 @@ public interface VeniceEngine extends SearchMode
public abstract void sendPasswordReminder(String username) public abstract void sendPasswordReminder(String username)
throws DataException, AccessError, EmailException; 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, public abstract UserContext createNewAccount(String remote_addr, String username, String password,
String reminder) throws DataException, AccessError; 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.dict.*;
import com.silverwrist.venice.htmlcheck.filters.*; import com.silverwrist.venice.htmlcheck.filters.*;
import com.silverwrist.venice.security.AuditRecord; import com.silverwrist.venice.security.AuditRecord;
import com.silverwrist.venice.security.PasswordGenerator;
import com.silverwrist.venice.security.PasswordHash; import com.silverwrist.venice.security.PasswordHash;
import com.silverwrist.venice.security.DefaultLevels; import com.silverwrist.venice.security.DefaultLevels;
@ -408,6 +409,64 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end class ConferenceCoreDataCreator } // 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 * 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 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 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 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 * Constructor
@ -1025,8 +1085,8 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
{ // look for a user name matching this user record { // look for a user name matching this user record
conn = datapool.getConnection(); conn = datapool.getConnection();
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
StringBuffer sql = new StringBuffer("SELECT c.email, u.passreminder FROM users u, contacts c WHERE " StringBuffer sql = new StringBuffer("SELECT c.email, u.uid, u.passreminder FROM users u, contacts c "
+ "u.contactid = c.contactid AND u.username = '"); + "WHERE u.contactid = c.contactid AND u.username = '");
sql.append(SQLUtil.encodeString(username)).append("';"); sql.append(SQLUtil.encodeString(username)).append("';");
ResultSet rs = stmt.executeQuery(sql.toString()); ResultSet rs = stmt.executeQuery(sql.toString());
if (!(rs.next())) if (!(rs.next()))
@ -1041,6 +1101,10 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("sendPasswordReminder(\"" + username + "\") going out to \"" + email_addr + "\""); 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. // Create the message to be sent.
String message = getStockMessage("reminder"); String message = getStockMessage("reminder");
if (message==null) if (message==null)
@ -1051,9 +1115,11 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end if } // end if
// Replace the message variables. // Replace the message variables.
HashMap vars = new HashMap(2); HashMap vars = new HashMap(4);
vars.put("username",username); 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); message = StringUtil.replaceAllVariables(message,vars);
// Find the message subject. // Find the message subject.
@ -1086,6 +1152,86 @@ public class VeniceEngineImpl implements VeniceEngine, EngineBackend
} // end sendPasswordReminder } // 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) public UserContext createNewAccount(String remote_addr, String username, String password, String reminder)
throws DataException, AccessError 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 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License. * 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>, * 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 * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are

View File

@ -0,0 +1,31 @@
<%--
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):
--%>
<%@ page import = "com.silverwrist.venice.servlets.format.*" %>
<%
RenderData rdat = RenderConfig.createRenderData(application,request,response);
%>
<% if (rdat.useHTMLComments()) { %><!-- Password changed --><% } %>
<% rdat.writeContentHeader(out,"Your Password Has Been Changed",null); %>
<%= rdat.getStdFontTag(ColorSelectors.CONTENT_FOREGROUND,2) %>
The password for your account has been changed, and a new password has been E-mailed to you at
your account's defined E-mail address. (Check your E-mail again!). After getting the new password,
please log in and change your password (yes, again!) as soon as possible.<P>
<DIV ALIGN="CENTER">
<A HREF="<%= rdat.getEncodedServletPath("top") %>">Return to Front Page</A>
</DIV>
</FONT>

View File

@ -7,7 +7,7 @@
WARRANTY OF ANY KIND, either express or implied. See the License for the specific WARRANTY OF ANY KIND, either express or implied. See the License for the specific
language governing rights and limitations under the License. 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>, 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 for Silverwrist Design Studios. Portions created by Eric J. Bowersox are