Commit d2360b6d authored by Leigh B. Stoller's avatar Leigh B. Stoller

A large set of authorization changes.

* Cleanup! A lot of the structure derived from the early frame days,
  which had a noticable (and bad) effect on how I wrote the stuff.  I
  cleaned up most of that yuckyness.

* In process, optimize a little bit on the queries. The old code did
  about 9 queries just to write out the menu options, and then
  repeated most of those queries again in the page guts. I've
  consolidated the queries as much as possible (to 3) and cache all
  the results.

* Fix up problem with users who forget their passwords before
  verification. Basically, I fixed the more general problem of not
  being able to update your user info before verification/approval;
  users now get that menu option no matter their status.

* Fix up problem of users being able to access pages before
  verification (but after approval) by going around the menu options.
  The page level check (after the menu is drawn) now checks all
  conditions (password expired, unverified, unapproved, timedout, and
  also nologins()).

* Minor change in approveuser; do not show the new account to the
  project leader until the new user has verified his account.

* Change verification method, as reqwuested by Dave.  In addition to
  providing the key, also provide a web link to take the user straight
  to verification. I actually take them direct to the login page, and
  pass the key in as an argument. If the user is already logged in,
  bypass and go directly to the verify page (not the form page of
  course).  If the user is not logged in, let him log in, and then
  forward the key onward to the verify page. Basically, bypass the
  form all the time, and just do the verification.

* Minor change in showuser; Do not show pid/groups not approved in,
  and if the count is zero, do not draw the table headings.
parent 3bfcfe9f
......@@ -118,7 +118,9 @@ $query_result =
"LEFT JOIN group_membership as authed ".
"ON g.pid=authed.pid and g.gid=authed.gid and ".
" g.uid!='$auth_usr' and g.trust='none' ".
"WHERE authed.uid='$auth_usr' and ".
"left join users as u on u.uid=g.uid ".
"WHERE u.status='" . TBDB_USERSTATUS_UNAPPROVED . "' and ".
" authed.uid='$auth_usr' and ".
" (authed.trust='group_root' or ".
" authed.trust='project_root') ".
"ORDER BY g.uid,g.pid,g.gid");
......
......@@ -28,11 +28,11 @@ $TBDB_IMAGEID_IMAGENAMELEN = 30;
#
# User status field.
#
$TBDB_USERSTATUS_ACTIVE = "active";
$TBDB_USERSTATUS_NEWUSER = "newuser";
$TBDB_USERSTATUS_UNAPPROVED = "unapproved";
$TBDB_USERSTATUS_UNVERIFIED = "unverified";
$TBDB_USERSTATUS_FROZEN = "frozen";
define("TBDB_USERSTATUS_ACTIVE", "active");
define("TBDB_USERSTATUS_NEWUSER", "newuser");
define("TBDB_USERSTATUS_UNAPPROVED", "unapproved");
define("TBDB_USERSTATUS_UNVERIFIED", "unverified");
define("TBDB_USERSTATUS_FROZEN", "frozen");
#
# Trust. Define the trust level as an increasing value. Then define a
......@@ -45,6 +45,15 @@ $TBDB_TRUST_GROUPROOT = 3;
$TBDB_TRUST_PROJROOT = 4;
$TBDB_TRUST_ADMIN = 5;
#
# Text strings in the DB for above.
#
define("TBDB_TRUSTSTRING_NONE", "none");
define("TBDB_TRUSTSTRING_USER", "user");
define("TBDB_TRUSTSTRING_LOCALROOT", "local_root");
define("TBDB_TRUSTSTRING_GROUPROOT", "group_root");
define("TBDB_TRUSTSTRING_PROJROOT", "project_root");
#
# These are the permission types. Different operations for the varying
# types of things we need to control access to.
......
......@@ -141,26 +141,6 @@ function FORMERROR($field) {
"Please go back and fill out the \"$field\" field!", 1);
}
#
# Is this user an admin type?
#
function ISADMIN($uid) {
global $TBDBNAME;
$query_result = mysql_db_query($TBDBNAME,
"SELECT admin FROM users WHERE uid='$uid'");
if (! $query_result) {
$err = mysql_error();
TBERROR("Database Error getting admin status for $uid: $err\n", 1);
}
$row = mysql_fetch_row($query_result);
$admin = $row[0];
return $admin;
}
#
# Run a program as a user.
#
......
......@@ -12,11 +12,12 @@ $uid = GETLOGIN();
#
# If a uid came in, then we check to see if the login is valid.
# If the login is not valid. We require that the user be logged in
# to start a second project.
# We require that the user be logged in to start a second project.
#
if ($uid) {
LOGGEDINORDIE($uid);
# Allow unapproved users to join multiple groups ...
# Must be verified though.
LOGGEDINORDIE($uid, CHECKLOGIN_UNAPPROVED);
$joining_uid = $uid;
$returning = 1;
}
......@@ -555,25 +556,25 @@ if (! $returning) {
$key = GENKEY($joining_uid);
TBMAIL("$usr_name '$joining_uid' <$usr_email>",
"Your New User Key",
"\n".
"Dear $usr_name ($joining_uid):\n\n".
"This is your account verification key: $key\n\n".
"Please return to:\n\n".
" $TBWWW\n\n".
"and log in using the user name and password you gave us when you\n".
"applied. You will then find an option on the menu called\n".
"'New User Verification'. Select this option, and on the page\n".
"enter your key. You will then be verified as a user. When you \n".
"have been both verified and approved by the project leader, you \n".
"will be marked as an active user, and will be granted full access\n".
"to your user account.\n\n".
"Thanks,\n".
"Testbed Ops\n".
"Utah Network Testbed\n",
"From: $TBMAIL_APPROVAL\n".
"Bcc: $TBMAIL_AUDIT\n".
"Errors-To: $TBMAIL_WWW");
"Your New User Key",
"\n".
"Dear $usr_name ($joining_uid):\n\n".
"This is your account verification key: $key\n\n".
"Please use this link to verify your user account:\n".
"\n".
" ${TBBASE}/login.php3?vuid=$joining_uid&key=$key\n".
"\n".
"Once you have verified your account, the project leader will be\n".
"able to approve you. You MUST verify your account before the project\n".
"leader can approve you. After project approval, you will be\n".
"marked as an active user, and will be granted full access to your\n".
"user account.\n\n".
"Thanks,\n".
"Testbed Ops\n".
"Utah Network Testbed\n",
"From: $TBMAIL_APPROVAL\n".
"Bcc: $TBMAIL_AUDIT\n".
"Errors-To: $TBMAIL_WWW");
}
#
......
......@@ -4,11 +4,29 @@
#
require("defs.php3");
#
# These two for verification.
#
if (!isset($key) || !strcmp($key, "")) {
$key = 0;
}
if (!isset($vuid) || !strcmp($vuid, "")) {
$vuid = 0;
}
#
# Must not be logged in already!
#
if (($known_uid = GETUID()) != FALSE) {
if (CHECKLOGIN($known_uid) == $CHECKLOGIN_LOGGEDIN) {
if (CHECKLOGIN($known_uid) & CHECKLOGIN_LOGGEDIN) {
#
# If doing a verification, zap to that page.
#
if ($key && (!$vuid || !strcmp($vuid, $known_uid))) {
header("Location: $TBBASE/verifyusr.php3?key=$key");
return;
}
PAGEHEADER("Login");
echo "<h3>
......@@ -24,7 +42,7 @@ if (($known_uid = GETUID()) != FALSE) {
#
# Spit out the form.
#
function SPITFORM($uid, $failed)
function SPITFORM($uid, $key, $failed)
{
global $TBDB_UIDLEN, $TBBASE;
......@@ -45,8 +63,12 @@ function SPITFORM($uid, $failed)
</font>
</center>\n";
$keyarg = "";
if ($key)
$keyarg = "?key=$key";
echo "<table align=center border=1>
<form action='${TBBASE}/login.php3' method=post>
<form action='${TBBASE}/login.php3${keyarg}' method=post>
<tr>
<td>Username:</td>
<td><input type=text
......@@ -69,18 +91,40 @@ function SPITFORM($uid, $failed)
</h2></center>\n";
}
#
# Do not bother if NOLOGINS!
#
if (NOLOGINS()) {
PAGEHEADER("Login");
echo "<center>
<font size=+1 color=red>
Logins are temporarily disabled. Please try again later.
</font>
</center><br>\n";
PAGEFOOTER();
die("");
}
#
# If not clicked, then put up a form.
#
if (! isset($login)) {
SPITFORM($known_uid, 0);
if ($vuid)
$known_uid = $vuid;
SPITFORM($known_uid, $key, 0);
PAGEFOOTER();
return;
}
#
# Login clicked.
#
#
$STATUS_LOGGEDIN = 1;
$STATUS_LOGINFAIL = 2;
$login_status = 0;
if (!isset($uid) ||
strcmp($uid, "") == 0) {
$login_status = $STATUS_LOGINFAIL;
......@@ -98,15 +142,23 @@ else {
# Failed, then try again with an error message.
#
if ($login_status == $STATUS_LOGINFAIL) {
SPITFORM($uid, 1);
SPITFORM($uid, $key, 1);
PAGEFOOTER();
return;
}
#
# Zap back to front page in secure mode.
#
header("Location: $TBBASE/");
if ($key) {
#
# If doing a verification, zap to that page.
#
header("Location: $TBBASE/verifyusr.php3?key=$key");
}
else {
#
# Zap back to front page in secure mode.
#
header("Location: $TBBASE/");
}
return;
?>
<?php
$STATUS_NOSTATUS = 0;
$STATUS_LOGGEDIN = 1;
$STATUS_LOGGEDOUT = 2;
$STATUS_LOGINFAIL = 3;
$STATUS_TIMEDOUT = 4;
$STATUS_NOLOGINS = 5;
$login_status = $STATUS_NOSTATUS;
$pswd_expired = 0;
$login_message = "";
$error_message = 0;
$login_status = CHECKLOGIN_NOTLOGGEDIN;
$login_uid = 0;
$drewheader = 0;
$javacode = file("java.html");
#
# This has to be set so we can spit out http or https paths properly!
......@@ -49,16 +39,13 @@ function WRITESIDEBARBUTTON($text, $base, $link) {
# sees depends on the login status and the DB status.
#
function WRITESIDEBAR() {
global $login_status, $login_message, $error_message, $login_uid;
global $STATUS_NOSTATUS, $STATUS_LOGGEDIN, $STATUS_LOGGEDOUT;
global $STATUS_LOGINFAIL, $STATUS_TIMEDOUT, $STATUS_NOLOGINS;
global $TBBASE, $TBDOCBASE, $TBDBNAME, $BASEPATH, $pswd_expired;
global $login_status, $login_uid;
global $TBBASE, $TBDOCBASE, $BASEPATH;
global $THISHOMEBASE;
#
# The document base cannot be a mix of secure and nonsecure.
#
#
echo "<table cellspacing=2 cellpadding=2 border=0 width=150>\n";
WRITESIDEBARBUTTON("Home", $TBDOCBASE, "index.php3");
......@@ -76,14 +63,14 @@ function WRITESIDEBAR() {
WRITESIDEBARBUTTON("Projects Using $THISHOMEBASE", $TBDOCBASE,
"projectlist.php3");
$freepcs = TBFreePCs();
echo "<tr>
<td height=30 valign=center align=center nowrap>
<b><span class=sidebarbutton>
Web Interface Options\n";
if ($login_status == $STATUS_LOGGEDIN) {
if ($login_status & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID)) {
$freepcs = TBFreePCs();
echo " <br>($freepcs Free PCs)\n";
}
echo " </span>
......@@ -91,124 +78,116 @@ function WRITESIDEBAR() {
</td>
</tr>\n";
if ($login_status == $STATUS_NOLOGINS) {
WRITESIDEBARBUTTON("Web Interface Temporarily Unavailable",
#
# Basically, we want to let admin people continue to use
# the web interface even when nologins set. But, we want to make
# it clear its disabled.
#
if (NOLOGINS()) {
WRITESIDEBARBUTTON("<font color=red> ".
"Web Interface Temporarily Unavailable</font>",
$TBDOCBASE, "nologins.php3");
echo "<tr>
<td height=30 valign=center align=center nowrap>
<b><span class=sidebarbutton>
Please Try Again Later
</span>
</b>
</td>
</tr>\n";
}
elseif ($login_status == $STATUS_LOGGEDIN) {
$query_result =
DBQueryFatal("SELECT status,admin ".
"FROM users WHERE uid='$login_uid'");
$row = mysql_fetch_row($query_result);
$status = $row[0];
$admin = $row[1];
#
# See if group_root in any projects, not just the last one in the DB!
#
$query_result = mysql_db_query($TBDBNAME,
"SELECT trust FROM group_membership ".
"WHERE uid='$login_uid' and ".
" (trust='group_root' or trust='project_root')");
if (mysql_num_rows($query_result)) {
$trusted = 1;
}
else {
$trusted = 0;
if (!$login_uid || !ISADMIN($login_uid)) {
echo "<tr>
<td height=30 valign=center align=center nowrap>
<b><span class=sidebarbutton>
Please Try Again Later
</span>
</b>
</td>
</tr>\n";
}
if ($status == "active" && $pswd_expired) {
WRITESIDEBARBUTTON("Change your Password",
$TBBASE, "moduserinfo.php3");
}
elseif ($status == "active") {
WRITESIDEBARBUTTON("My $THISHOMEBASE",
$TBBASE,
"showuser.php3?target_uid=$login_uid");
if ($admin) {
WRITESIDEBARBUTTON("New Project Approval",
$TBBASE, "approveproject_list.php3");
}
if ($trusted) {
# Only project leaders can do these options
WRITESIDEBARBUTTON("New User Approval",
$TBBASE, "approveuser_form.php3");
}
if ($login_status & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID)) {
if ($login_status & CHECKLOGIN_ACTIVE) {
if ($login_status & CHECKLOGIN_PSWDEXPIRED) {
WRITESIDEBARBUTTON("Change your Password",
$TBBASE, "moduserinfo.php3");
}
#
# Since a user can be a member of more than one project,
# display this option, and let the form decide if the user is
# allowed to do this.
#
WRITESIDEBARBUTTON("Project Information",
$TBBASE, "showproject_list.php3");
else {
WRITESIDEBARBUTTON("My $THISHOMEBASE",
$TBBASE,
"showuser.php3?target_uid=$login_uid");
if ($admin) {
WRITESIDEBARBUTTON("User List",
$TBBASE, "showuser_list.php3");
WRITESIDEBARBUTTON("Node Control",
$TBBASE, "nodecontrol_list.php3");
}
if ($login_status & CHECKLOGIN_ISADMIN) {
WRITESIDEBARBUTTON("New Project Approval",
$TBBASE, "approveproject_list.php3");
}
if ($login_status & CHECKLOGIN_TRUSTED) {
# Only project/group leaders can do these options
WRITESIDEBARBUTTON("New User Approval",
$TBBASE, "approveuser_form.php3");
}
#
# Since a user can be a member of more than one project,
# display this option, and let the form decide if the user is
# allowed to do this.
#
WRITESIDEBARBUTTON("Project Information",
$TBBASE, "showproject_list.php3");
WRITESIDEBARBUTTON("Begin an Experiment",
$TBBASE, "beginexp.php3");
WRITESIDEBARBUTTON("Experiment Information",
$TBBASE, "showexp_list.php3");
WRITESIDEBARBUTTON("Update user information",
$TBBASE, "moduserinfo.php3");
WRITESIDEBARBUTTON("Node Reservation Status",
$TBBASE, "reserved.php3");
WRITESIDEBARBUTTON("Node Up/Down Status",
$TBDOCBASE, "updown.php3");
if (TBCvswebAllowed($login_uid)) {
WRITESIDEBARBUTTON("CVS Repository",
$TBBASE, "cvsweb/cvsweb.php3");
if ($login_status & CHECKLOGIN_ISADMIN) {
WRITESIDEBARBUTTON("User List",
$TBBASE, "showuser_list.php3");
WRITESIDEBARBUTTON("Node Control",
$TBBASE, "nodecontrol_list.php3");
}
WRITESIDEBARBUTTON("Begin an Experiment",
$TBBASE, "beginexp.php3");
WRITESIDEBARBUTTON("Experiment Information",
$TBBASE, "showexp_list.php3");
WRITESIDEBARBUTTON("Update user information",
$TBBASE, "moduserinfo.php3");
WRITESIDEBARBUTTON("Node Reservation Status",
$TBBASE, "reserved.php3");
WRITESIDEBARBUTTON("Node Up/Down Status",
$TBDOCBASE, "updown.php3");
if ($login_status & CHECKLOGIN_CVSWEB) {
WRITESIDEBARBUTTON("CVS Repository",
$TBBASE, "cvsweb/cvsweb.php3");
}
}
}
elseif (($status == "newuser") || ($status == "unverified")) {
elseif ($login_status & (CHECKLOGIN_UNVERIFIED|CHECKLOGIN_NEWUSER)) {
WRITESIDEBARBUTTON("New User Verification",
$TBBASE, "verifyusr_form.php3");
WRITESIDEBARBUTTON("Update user information",
$TBBASE, "moduserinfo.php3");
}
elseif ($status == "unapproved") {
$error_message = "Your account has not been approved yet. ".
"Please try back later";
elseif ($login_status & (CHECKLOGIN_UNAPPROVED)) {
WRITESIDEBARBUTTON("Update user information",
$TBBASE, "moduserinfo.php3");
}
}
#
# Standard options for anyone.
#
if ($login_status != $STATUS_NOLOGINS) {
if (! NOLOGINS()) {
WRITESIDEBARBUTTON("Start Project", $TBBASE, "newproject.php3");
WRITESIDEBARBUTTON("Join Project", $TBBASE, "joinproject.php3");
}
switch ($login_status) {
case $STATUS_LOGGEDIN:
#
# Cons up a nice message.
#
switch ($login_status & CHECKLOGIN_STATUSMASK) {
case CHECKLOGIN_LOGGEDIN:
$login_message = "$login_uid Logged In";
if ($pswd_expired)
if ($login_status & CHECKLOGIN_PSWDEXPIRED)
$login_message = "$login_message<br>(Password Expired!)";
elseif ($login_status & CHECKLOGIN_UNAPPROVED)
$login_message = "$login_message<br>(Unapproved!)";
break;
case $STATUS_LOGGEDOUT:
$login_message = "Logged Out";
break;
case $STATUS_LOGINFAIL:
$login_message = "Login Failed";
break;
case $STATUS_TIMEDOUT:
case CHECKLOGIN_TIMEDOUT:
$login_message = "Login Timed Out";
break;
case $STATUS_NOLOGINS:
$login_message = "Please Try Again Later";
default:
$login_message = 0;
break;
}
......@@ -219,7 +198,7 @@ function WRITESIDEBAR() {
# http or https, since we do not want to mix them, since they
# cause warnings.
#
if ($login_status == $STATUS_LOGGEDIN) {
if ($login_status & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID)) {
echo "<tr>
<td align=center height=50 valign=center>
<a href=\"$TBBASE/logout.php3?uid=$login_uid\">
......@@ -228,7 +207,7 @@ function WRITESIDEBAR() {
</td>
</tr>\n";
}
else {
elseif (!NOLOGINS()) {
echo "<tr>
<td align=center height=50 valign=center>
<a href=\"$TBBASE/login.php3\">
......@@ -249,13 +228,12 @@ function WRITESIDEBAR() {
</td>
</tr>\n";
}
#
# MOTD. Set this with the webcontrol script.
#
# The blinking is for Mike, who says he really likes it.
#
$query_result = mysql_db_query($TBDBNAME,
"SELECT message FROM loginmessage");
$query_result =
DBQueryFatal("SELECT message FROM loginmessage");
if (mysql_num_rows($query_result)) {
$row = mysql_fetch_row($query_result);
......@@ -286,12 +264,6 @@ function WRITEBANNER($title) {
echo "<!-- This is the page Banner -->\n";
# echo "
# <a href='$BASEPATH/pix/merge-med.jpg'>
# <img src='$BASEPATH/pix/merge-mini.jpg'
# border=2 align=right></a>
# \n";
echo "<table cellpadding=0 cellspacing=0 border=0 width=50%>";
echo "<tr>
<td align=left valign=top width=\"0%\">
......@@ -351,14 +323,8 @@ function WRITETITLE($title) {
# Spit out a vanilla page header.
#
function PAGEHEADER($title) {
global $login_status, $TBAUTHTIMEOUT, $login_uid;
global $STATUS_NOSTATUS, $STATUS_LOGGEDIN, $STATUS_LOGGEDOUT;
global $STATUS_LOGINFAIL, $STATUS_TIMEDOUT, $STATUS_NOLOGINS;
global $TBBASE, $TBDOCBASE, $TBDBNAME;
global $CHECKLOGIN_NOTLOGGEDIN, $CHECKLOGIN_LOGGEDIN;
global $CHECKLOGIN_TIMEDOUT, $CHECKLOGIN_MAYBEVALID;
global $CHECKLOGIN_PSWDEXPIRED, $THISHOMEBASE
global $BASEPATH, $SSL_PROTOCOL, $javacode, $drewheader, $pswd_expired;
global $login_status, $login_uid, $TBBASE, $TBDOCBASE, $THISHOMEBASE;
global $BASEPATH, $SSL_PROTOCOL, $drewheader;
global $TBMAINSITE;
$drewheader = 1;
......@@ -386,46 +352,23 @@ function PAGEHEADER($title) {
#
# Check to make sure the UID is logged in (not timed out).
#
$status = CHECKLOGIN($known_uid);
switch ($status) {
case $CHECKLOGIN_NOTLOGGEDIN:
$login_status = $STATUS_NOSTATUS;
$login_uid = 0;
break;
case $CHECKLOGIN_PSWDEXPIRED:
$pswd_expired = 1;
case $CHECKLOGIN_LOGGEDIN:
case $CHECKLOGIN_MAYBEVALID:
$login_status = $STATUS_LOGGEDIN;
$login_uid = $known_uid;
break;
case $CHECKLOGIN_TIMEDOUT:
$login_status = $STATUS_TIMEDOUT;
$login_uid = 0;
break;
$login_status = CHECKLOGIN($known_uid);
if ($login_status & (CHECKLOGIN_LOGGEDIN|CHECKLOGIN_MAYBEVALID)) {
$login_uid = $known_uid;
}
}
#
# Check for NOLOGINS. This is complicated by the fact that we
# want to allow admin types to continue using the web interface,
# Check for NOLOGINS.
# We want to allow admin types to continue using the web interface,
# and logout anyone else that is currently logged in!
#
if ($login_status == $STATUS_LOGGEDIN && NOLOGINS()) {
$query_result = mysql_db_query($TBDBNAME,
"SELECT admin FROM users WHERE uid='$login_uid'");
$row = mysql_fetch_row($query_result);
$admin = $row[0];
if (!$admin) {
DOLOGOUT($login_uid);
$login_status = $STATUS_NOLOGINS;
}
}
elseif (NOLOGINS()) {