Commit 315e11ab authored by Leigh Stoller's avatar Leigh Stoller

New pages to allow users to reset their forgotten passwords without

invovling testbed ops. Split into two parts:

* password.php3 gives the user a form to specify their email address
  and their phone number. We look for a match in the DB, with the
  phone number stripped of all non-numeric characters and the email
  addresses lowercased. If we find a matching user in the database,
  generate a unique key and store that into the DB along with a
  timestamp that allows the key to be used for a short time period
  (currently 30 minutes). The key is split into two parts, with half
  stored in the users browser (secure mode), and the other half sent
  to the user in an email message that contains a URL that allows the
  user to reset their password.

* chpasswd.php3 does the rest of the operation. It takes half the key
  from the URL, and sucks the other half from the user's browser,
  combining the two halves and matching it against the key that is
  stored in the DB. If the key matches and the timeout has not
  expired, the user is given a form to specify a new password. From
  this point on its just a standard change password operation.

Both pages are audited with email sent to the user, tbops and the
audit list.
parent 1fbefb43
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
# Display a simpler version of this page
$simple = 0;
if (isset($_REQUEST['simple'])) {
$simple = $_REQUEST['simple'];
}
# Form arguments.
$reset_uid = $_REQUEST['reset_uid'];
$keyB = $_REQUEST['key'];
# We also need the other half of the key from the browser.
$keyA = $HTTP_COOKIE_VARS[$TBAUTHCOOKIE];
if (!isset($reset_uid) || $reset_uid == "" || !TBvalid_uid($reset_uid) ||
!isset($keyA) || $keyA == "" || !preg_match("/^[\w]+$/", $keyA) ||
!isset($keyB) || $keyB == "" || !preg_match("/^[\w]+$/", $keyB)) {
PAGEARGERROR();
}
# The complete key.
$key = $keyA . $keyB;
# Must use https!
if (!isset($SSL_PROTOCOL)) {
PAGEHEADER("Reset Your Password", $view);
USERERROR("Must use https:// to access this page!", 1);
}
#
# Turn off some of the decorations and menus for the simple view
#
if ($simple) {
$view = array('hide_banner' => 1, 'hide_copyright' => 1,
'hide_sidebar' => 1);
} else {
$view = array();
}
#
# Must not be logged in.
#
if (($known_uid = GETUID()) != FALSE) {
if (CHECKLOGIN($known_uid) & CHECKLOGIN_LOGGEDIN) {
PAGEHEADER("Reset Your Password", $view);
echo "<h3>
You are logged in. You must already know your password!
</h3>\n";
PAGEFOOTER($view);
die("");
}
}
#
# Spit out the form.
#
function SPITFORM($uid, $key, $failed, $simple, $view)
{
global $TBBASE;
PAGEHEADER("Reset Your Password", $view);
if ($failed) {
echo "<center>
<font size=+1 color=red>
$failed. Please try again.
</font>
</center><br>\n";
}
else {
echo "<center>
<font size=+1>
Please enter a new password.<br><br>
</font>
</center>\n";
}
$args = "reset_uid=$uid&key=$key&simple=$simple";
echo "<table align=center border=1>
<form action=${TBBASE}/chpasswd.php3?${args} method=post>\n";
echo "<tr>
<td>Password:</td>
<td class=left>
<input type=password
name=\"password1\"
size=12></td>
</tr>\n";
echo "<tr>
<td>Retype Password:</td>
<td class=left>
<input type=password
name=\"password2\"
size=12></td>
</tr>\n";
echo "<tr>
<td align=center colspan=2>
<b><input type=submit value=\"Reset Password\"
name=reset></b></td>
</tr>\n";
echo "</form>
</table>\n";
}
#
# Check to make sure that the key is valid and that the timeout has not
# expired.
#
$query_result =
DBQueryFatal("select chpasswd_key,chpasswd_expires,usr_email,usr_name ".
" from users ".
"where uid='$reset_uid'");
# Silent error about invalid users.
if (!mysql_num_rows($query_result)) {
PAGEARGERROR();
}
$row = mysql_fetch_row($query_result);
$usr_email = $row[2];
$usr_name = $row[3];
# Silent error when there is no key/timeout set for the user.
if (!isset($row[0]) || !$row[1]) {
PAGEARGERROR();
}
if ($row[0] != $key) {
USERERROR("You do not have permission to change your password!", 1);
}
if (time() > $row[1]) {
USERERROR("Your key has expired. Please request a
<a href='password.php3'>new key</a>.", 1);
}
#
# If not clicked, then put up a form.
#
if (! isset($reset)) {
SPITFORM($reset_uid, $keyB, 0, $simple, $view);
return;
}
#
# Reset clicked. Verify a proper password.
#
$password1 = $_POST['password1'];
$password2 = $_POST['password2'];
if (!isset($password1) || $password1 == "" ||
!isset($password2) || $password2 == "") {
SPITFORM($reset_uid, $keyB, "You must supply a password", $simple, $view);
return;
}
if ($password1 != $password2) {
SPITFORM($reset_uid, $keyB, "Two passwords do not match", $simple, $view);
return;
}
if (! CHECKPASSWORD($reset_uid, $password1, $usr_name, $usr_email, $checkerror)){
SPITFORM($reset_uid, $keyB, $checkerror, $simple, $view);
return;
}
# Clear the cookie from the browser.
setcookie($TBAUTHCOOKIE, "", time() - 1000000, "/", $TBAUTHDOMAIN, 0);
# Okay to spit this now that the cookie has been sent (cleared).
PAGEHEADER("Reset Your Password", $view);
$encoding = crypt("$password1");
$expires = "date_add(now(), interval 1 year)";
DBQueryFatal("update users set ".
" chpasswd_key=NULL,chpasswd_expires=0, ".
" usr_pswd='$encoding',pswd_expires=$expires ".
"where uid='$reset_uid'");
if (HASREALACCOUNT($reset_uid)) {
SUEXEC($reset_uid, "nobody", "webtbacct passwd $reset_uid", 1);
}
TBMAIL("$usr_name <$usr_email>",
"Password Reset for '$reset_uid'",
"\n".
"The password for '$reset_uid' has been reset via the web interface.\n".
"If this message is unexpected, please contact Testbed Operations\n".
"($TBMAILADDR_OPS) immediately!\n".
"\n".
"The change originated from IP: " . $_SERVER['REMOTE_ADDR'] . "\n".
"\n".
"Thanks,\n".
"Testbed Operations\n",
"From: $TBMAIL_OPS\n".
"Bcc: $TBMAIL_AUDIT\n".
"Errors-To: $TBMAIL_WWW");
echo "<br>
Your password has been changed.\n";
#
# Standard Testbed Footer
#
PAGEFOOTER();
?>
......@@ -131,7 +131,7 @@ function SPITFORM($uid, $key, $referrer, $failed, $adminmode, $simple, $view)
</table>\n";
echo "<center><h2>
<a href='password.php3'>Forgot your password?</a>
<a href='password.php3'>Forgot your username or password?</a>
</h2></center>\n";
}
......@@ -159,6 +159,8 @@ if (!isset($uid) || $uid == "" || !isset($password) || $password == "") {
}
else {
if (DOLOGIN($uid, $password, $adminmode)) {
# Short delay.
sleep(1);
$login_status = $STATUS_LOGINFAIL;
}
else {
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
# Display a simpler version of this page
$simple = 0;
if (isset($_REQUEST['simple'])) {
$simple = $_REQUEST['simple'];
}
# Form arguments.
$reset = $_POST['reset'];
$email = $_POST['email'];
$phone = $_POST['phone'];
#
# Standard Testbed Header
# Turn off some of the decorations and menus for the simple view
#
PAGEHEADER("Forgot Your Password?");
if ($simple) {
$view = array('hide_banner' => 1, 'hide_copyright' => 1,
'hide_sidebar' => 1);
} else {
$view = array();
}
echo "<p>
So you've forgotten your password. Happens to all of us!
# Must use https!
if (!isset($SSL_PROTOCOL)) {
PAGEHEADER("Forgot Your Password?", $view);
USERERROR("Must use https:// to access this page!", 1);
}
<p>
Unfortunately, we don't do those little reminder hints like \"What was
your first dog's maiden name?.\"
#
# Must not be logged in.
#
if (($known_uid = GETUID()) != FALSE) {
if (CHECKLOGIN($known_uid) & CHECKLOGIN_LOGGEDIN) {
PAGEHEADER("Forgot Your Password?", $view);
<p>
If you are a <b>project member</b> then please send email to your
project or group leader. She/He can change your password for you via
the 'Update User Information' menu item.
echo "<h3>
You are logged in. You must already know your password!
</h3>\n";
<p>
If you are a <b>project leader</b>, then send us an
<a href='mailto:$TBMAILADDR_OPS?subject=I forgot my password'>email
message</a>, and we will fix things up for you!\n";
PAGEFOOTER($view);
die("");
}
}
#
# Standard Testbed Footer
# Spit out the form.
#
PAGEFOOTER();
?>
function SPITFORM($email, $phone, $failed, $simple, $view)
{
global $TBBASE;
PAGEHEADER("Forgot Your Password?", $view);
if ($failed) {
echo "<center>
<font size=+1 color=red>
The email/phone ($failed) you provided does not match. Please try again.
</font>
</center><br>\n";
}
else {
echo "<center>
<font size=+1>
Please provide your email address and phone number.<br><br>
</font>
</center>\n";
}
echo "<table align=center border=1>
<form action=${TBBASE}/password.php3 method=post>
<tr>
<td>Email Address:</td>
<td><input type=text
value=\"$email\"
name=email size=30></td>
</tr>
<tr>
<td>Phone Number:</td>
<td><input type=text
value=\"$phone\"
name=phone size=20></td>
</tr>
<tr>
<td align=center colspan=2>
<b><input type=submit value=\"Reset Password\"
name=reset></b></td>
</tr>\n";
if ($simple) {
echo "<input type=hidden name=simple value=$simple>\n";
}
echo "</form>
</table>\n";
echo "<br><blockquote>
Please provide your phone number in standard dashed notation;
no extensions or room numbers, etc. We will do our best to match it up
against our user records.
<br><br>
If the email address and phone number you give us matches
our user records, we will email a URL that will allow you to change
your password.
</blockquote>\n";
}
#
# If not clicked, then put up a form.
#
if (! isset($reset)) {
SPITFORM("", "", 0, $simple, $view);
return;
}
#
# Reset clicked. See if we find a user with the given email/phone. If not
# zap back to the form.
#
if (!isset($phone) || $phone == "" || !TBvalid_phone($phone) ||
!isset($email) || $email == "" || !TBvalid_email($email)) {
SPITFORM($email, $phone, 1, $simple, $view);
return;
}
$query_result =
DBQueryFatal("select uid,usr_phone from users ".
"where LCASE(usr_email)=LCASE('$email')");
if (! mysql_num_rows($query_result)) {
SPITFORM($email, $phone, 2, $simple, $view);
return;
}
$row = mysql_fetch_row($query_result);
$uid = $row[0];
$usr_phone = $row[1];
#
# Compare phone by striping out anything but the numbers.
#
if (preg_replace("/[^0-9]/", "", $phone) !=
preg_replace("/[^0-9]/", "", $usr_phone)) {
SPITFORM($email, $phone, 3, $simple, $view);
return;
}
#
# Yep. Generate a random key and send the user an email message with a URL
# that will allow them to change their password.
#
$key = md5(uniqid(rand(),1));
$keyA = substr($key, 0, 16);
$keyB = substr($key, 16);
# Send half of the key to the browser and half in the email message.
setcookie($TBAUTHCOOKIE, $keyA, 0, "/",
$TBAUTHDOMAIN, $TBSECURECOOKIES);
# It is okay to spit this now that we have sent the cookie.
PAGEHEADER("Forgot Your Password?", $view);
DBQueryFatal("update users set ".
" chpasswd_key='$key', ".
" chpasswd_expires=UNIX_TIMESTAMP(now())+(60*30) ".
"where uid='$uid'");
TBUserInfo($uid, $uid_name, $uid_email);
TBMAIL("$uid_name <$uid_email>",
"Password Reset requested by '$uid'",
"\n".
"Here is your password reset authorization URL. Click on this link\n".
"within the next 30 minutes, and you will be allowed to reset your\n".
"password. If the link expires, you can request a new one from the\n".
"web interface.\n".
"\n".
" ${TBBASE}/chpasswd.php3?reset_uid=$uid&key=$keyB&simple=$simple\n".
"\n".
"The request originated from IP: " . $_SERVER['REMOTE_ADDR'] . "\n".
"\n".
"Thanks,\n".
"Testbed Operations\n",
"From: $TBMAIL_OPS\n".
"Bcc: $TBMAIL_AUDIT\n".
"Errors-To: $TBMAIL_WWW");
echo "<br>
An email message has been sent to your account. In it you will find a
URL that will allow you to change your password. The link will <b>expire
in 30 minutes</b>. If the link does expire before you have a chance to
use it, simply come back and request a <a href='password.php3'>new one</a>.
\n";
#
# Standard Testbed Footer
#
PAGEFOOTER();
?>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment