Commit 90dcbbe2 authored by Leigh B. Stoller's avatar Leigh B. Stoller

Okay, I think I am finally done with WikiWhacking (or WhackingTheWiki?)

for the near future. Two big changes:

* Add WikiOnly accounts. An external user can register for an account on
  the wiki. Rather then use the registration stuff that comes with TWiki,
  redirect to new Emulab web page so we can manage all of the wiki accounts
  from one place. I modified the joinproject page to spit out a subset of
  the required fields so that its simple to get a wiki only account (just a
  few things to fill in).

  In keeping with current security practices, we still generate a
  verification email message to ensure the email address works. However,
  when the user completes the verification, the wiki account is created right
  away, rather then waiting for someone to approve it (since that would
  defeat the entire point of the wiki).

  Aside: I have not thought much about the conversion from a wiki-only
  account to a real account. That is going to happen, and it would be nice
  if that step did not require one of use to go in and hack the DB. Will
  cross that moat later.

  Aside: Rather beat up on the modify user info page too much, I continue
  to spit out the same form, but mark most of the fields as not required,
  and allow wiki-only people to not specify them.

* Both the joinproject and newproject pages sport a new WikiName field so
  that users can select their own WikiName. I added some JavaScript to
  both pages that generate a suitable wikiname from the FullName field, so
  that as soon as the user clicks out of the FullName, a default wikiname is
  inserted in the field.

  Both pages verify the wikinames by checking to make sure it is not
  already in use, and that it meets the WikiRules for WikiTopic names.
  (someone please shoot me if I continue to use WikiNotation).
parent 1b22ebcc
......@@ -58,6 +58,7 @@ ifeq ($(EVENTSYS),1)
endif
@$(MAKE) -C mote post-install
@$(MAKE) -C tools post-install
@$(MAKE) -C wiki post-install
#
# For installation on the 'ops' or 'users' node (okay, plastic)
......
......@@ -167,7 +167,8 @@ if (AuditStart(0)) {
#
$query_result =
DBQueryFatal("select u.usr_pswd,u.unix_uid,u.usr_name, ".
" u.usr_email,u.status,u.webonly,u.usr_shell,admin,u.usr_w_pswd ".
" u.usr_email,u.status,u.webonly,u.usr_shell,admin, ".
" u.usr_w_pswd,u.wikionly ".
"from users as u ".
"where u.uid='$user'");
......@@ -184,6 +185,7 @@ my $webonly = $row[5];
my $usr_shell = $row[6];
my $usr_admin = $row[7];
my $wpswd = $row[8];
my $wikionly = $row[9];
#
# Get the users earliest project membership to use as the default group
......@@ -273,10 +275,20 @@ sub AddUser()
#
# Check status. Only active users get accounts built.
#
if ($webonly || $status ne USERSTATUS_ACTIVE) {
if ($webonly || $wikionly || $status ne USERSTATUS_ACTIVE) {
if ($webonly) {
return 0;
}
if ($wikionly) {
$EUID = $UID;
# And to the wiki if enabled.
system("$ADDWIKIUSER $user")
if ($WIKISUPPORT && !$batch);
$EUID = 0;
return 0;
}
fatal("$user is not active! Cannot build an account!");
}
......
......@@ -200,6 +200,10 @@ function TBvalid_usrname($token) {
return TBcheck_dbslot($token, "users", "usr_name",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR);
}
function TBvalid_wikiname($token) {
return TBcheck_dbslot($token, "users", "wikiname",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR);
}
function TBvalid_email($token) {
return TBcheck_dbslot($token, "users", "usr_email",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR);
......
......@@ -863,6 +863,21 @@ function TBCurrentUser($uid)
return mysql_num_rows($query_result);
}
#
# Confirm a current WikiName or not.
#
# usage TBCurrentWikiName($uid)
# returns 1 if a current wikiname.
# returns 0 if not a current wikiname
#
function TBCurrentWikiName($wikiname)
{
$query_result =
DBQueryFatal("SELECT usr_pswd FROM users WHERE wikiname='$wikiname'");
return mysql_num_rows($query_result);
}
#
# Check to see if an email is being used twice.
#
......@@ -1502,6 +1517,14 @@ function TBCvswebAllowed($uid) {
return mysql_num_rows($query_result);
}
function TBWikiOnlyUser($uid) {
$query_result =
DBQueryFatal("select wikionly from users ".
"WHERE uid='$uid' and wikionly=1");
return mysql_num_rows($query_result);
}
#
# Returns > 0 if a node has a serial console, 0 if it does not
#
......
......@@ -22,7 +22,8 @@ $uid = GETLOGIN();
if ($uid) {
# Allow unapproved users to join multiple groups ...
# Must be verified though.
LOGGEDINORDIE($uid, CHECKLOGIN_UNAPPROVED|CHECKLOGIN_WEBONLY);
LOGGEDINORDIE($uid, CHECKLOGIN_UNAPPROVED|
CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
$joining_uid = $uid;
$returning = 1;
}
......@@ -33,6 +34,10 @@ else {
$returning = 0;
}
if (!isset($forwikionly)) {
$forwikionly = 0;
}
$ACCOUNTWARNING =
"Before continuing, please make sure your username " .
"reflects your normal login name. ".
......@@ -50,15 +55,32 @@ function SPITFORM($formfields, $returning, $errors)
{
global $TBDB_UIDLEN, $TBDB_PIDLEN, $TBDB_GIDLEN;
global $ACCOUNTWARNING, $EMAILWARNING;
global $WIKISUPPORT, $forwikionly, $WIKIURL;
if ($forwikionly)
PAGEHEADER("Wiki Registration");
else
PAGEHEADER("Apply for Project Membership");
if (! $returning) {
echo "<center><font size=+1>
echo "<center>\n";
if ($forwikionly) {
echo "<font size=+2>Register for an Emulab Wiki account</font>
<br><br>\n";
}
echo "<font size=+1>
If you already have an Emulab account,
<a href=login.php3?refer=1>
<font color=red>please log on first!</font></a>
</font></center><br>\n";
</font>\n";
if ($forwikionly) {
echo "<br>(You will already have a wiki account)\n";
}
echo "</center><br>\n";
}
elseif ($forwikionly) {
USERERROR("You already have a Wiki account!", 1);
}
if ($errors) {
......@@ -82,6 +104,34 @@ function SPITFORM($formfields, $returning, $errors)
}
echo "</table><br>\n";
}
echo "<SCRIPT LANGUAGE=JavaScript>
function SetWikiName(theform)
{
var validchars = 'abcdefghijklmnopqrstuvwxyz0123456789';
var usrname = theform['formfields[usr_name]'].value;
var wikiname = '';
var docap = 1;
for (var i = 0; i < usrname.length; i++) {
var letter = usrname.charAt(i).toLowerCase();
if (validchars.indexOf(letter) == -1) {
if (letter == ' ') {
docap = 1;
}
continue;
}
else {
if (docap == 1) {
letter = usrname.charAt(i).toUpperCase()
docap = 0;
}
wikiname = wikiname + letter;
}
}
theform['formfields[wikiname]'].value = wikiname;
}
</SCRIPT>\n";
echo "<table align=center border=1>
<tr>
......@@ -90,8 +140,10 @@ function SPITFORM($formfields, $returning, $errors)
</td>
</tr>\n
<form enctype=multipart/form-data
action=joinproject.php3 method=post>\n";
<form name=myform enctype=multipart/form-data
action=" . ($forwikionly ?
"wikiregister.php3" : "joinproject.php3") . " " .
"method=post>\n";
if (! $returning) {
#
......@@ -117,11 +169,29 @@ function SPITFORM($formfields, $returning, $errors)
<td class=left>
<input type=text
name=\"formfields[usr_name]\"
onchange=\"SetWikiName(myform);\"
value=\"" . $formfields[usr_name] . "\"
size=30>
</td>
</tr>\n";
#
# WikiName
#
if ($WIKISUPPORT) {
echo "<tr>
<td colspan=2>*
<a href=${WIKIURL}/TWiki/WikiName
target=_blank>WikiName</a>:<td class=left>
<input type=text
name=\"formfields[wikiname]\"
value=\"" . $formfields[wikiname] . "\"
size=30>
</td>
</tr>\n";
}
if (! $forwikionly) {
#
# Title/Position:
#
......@@ -160,6 +230,7 @@ function SPITFORM($formfields, $returning, $errors)
size=45>
</td>
</tr>\n";
}
#
# Email:
......@@ -175,6 +246,10 @@ function SPITFORM($formfields, $returning, $errors)
</td>
</tr>\n";
if (! $forwikionly) {
#
# Postal Address
#
echo "<tr><td colspan=3>*Postal Address:<br /><center>
<table>
<tr><td>Line 1</td><td colspan=3>
......@@ -240,7 +315,8 @@ function SPITFORM($formfields, $returning, $errors)
<input type=hidden name=MAX_FILE_SIZE value=1024>
<input type=file
name=usr_keyfile
value=\"" . $_FILES['usr_keyfile']['name'] . "\"
value=\"" . $_FILES['usr_keyfile']['name'] .
"\"
size=50>
<br>
<br>
......@@ -251,6 +327,7 @@ function SPITFORM($formfields, $returning, $errors)
maxlength=1024>
</td>
</tr>\n";
}
#
# Password. Note that we do not resend the password. User
......@@ -273,6 +350,7 @@ function SPITFORM($formfields, $returning, $errors)
</tr>\n";
}
if (! $forwikionly) {
#
# Project Name:
#
......@@ -299,6 +377,7 @@ function SPITFORM($formfields, $returning, $errors)
size=$TBDB_GIDLEN maxlength=$TBDB_GIDLEN>
</td>
</tr>\n";
}
echo "<tr>
<td colspan=3 align=center>
......@@ -315,7 +394,7 @@ function SPITFORM($formfields, $returning, $errors)
<a href = 'docwrapper.php3?docname=security.html'>
security policies</a> for information
regarding passwords and email addresses.\n";
if (! $returning) {
if (!$returning && !$forwikionly) {
echo "<li> If you want us to use your existing ssh public key,
then either paste it in or specify the path to your
your identity.pub file. <font color=red>NOTE:</font>
......@@ -342,12 +421,21 @@ function SPITFORM($formfields, $returning, $errors)
# The conclusion of a join request. See below.
#
if (isset($_GET['finished'])) {
if ($forwikionly)
PAGEHEADER("Wiki Registration");
else
PAGEHEADER("Apply for Project Membership");
#
# Generate some warm fuzzies.
#
if (! $returning) {
if ($forwikionly) {
echo "An email message has been sent to your account so we may verify
your email address. Please follow the instructions contained in
that message, which will verify your account, and grant you
access to the Wiki.\n";
}
elseif (! $returning) {
echo "<p>
As a pending user of the Testbed you will receive a key via email.
When you receive the message, please follow the instructions
......@@ -356,7 +444,8 @@ if (isset($_GET['finished'])) {
<p>
When you have done that, the project leader will be
notified of your application. ";
} else {
}
else {
echo "<p>
The project leader has been notified of your application. ";
}
......@@ -420,13 +509,6 @@ if (! $returning) {
posix_getpwnam($formfields[joining_uid])) {
$errors["UserName"] = "Already in use. Pick another";
}
if (!isset($formfields[usr_title]) ||
strcmp($formfields[usr_title], "") == 0) {
$errors["Title/Position"] = "Missing Field";
}
elseif (! TBvalid_title($formfields[usr_title])) {
$errors["Title/Position"] = TBFieldErrorString();
}
if (!isset($formfields[usr_name]) ||
strcmp($formfields[usr_name], "") == 0) {
$errors["Full Name"] = "Missing Field";
......@@ -440,7 +522,26 @@ if (! $returning) {
if (count($tokens) < 2) {
$errors["Full Name"] = "Please provide a first and last name";
}
if ($WIKISUPPORT) {
if (!isset($formfields[wikiname]) ||
strcmp($formfields[wikiname], "") == 0) {
$errors["WikiName"] = "Missing Field";
}
elseif (! TBvalid_wikiname($formfields[wikiname])) {
$errors["WikiName"] = TBFieldErrorString();
}
elseif (TBCurrentWikiName($formfields[wikiname])) {
$errors["WikiName"] = "Already in use. Pick another";
}
}
if (!$forwikionly) {
if (!isset($formfields[usr_title]) ||
strcmp($formfields[usr_title], "") == 0) {
$errors["Title/Position"] = "Missing Field";
}
elseif (! TBvalid_title($formfields[usr_title])) {
$errors["Title/Position"] = TBFieldErrorString();
}
if (!isset($formfields[usr_affil]) ||
strcmp($formfields[usr_affil], "") == 0) {
$errors["Affiliation"] = "Missing Field";
......@@ -448,6 +549,7 @@ if (! $returning) {
elseif (! TBvalid_affiliation($formfields[usr_affil])) {
$errors["Affiliation"] = TBFieldErrorString();
}
}
if (!isset($formfields[usr_email]) ||
strcmp($formfields[usr_email], "") == 0) {
$errors["Email Address"] = "Missing Field";
......@@ -465,6 +567,7 @@ if (! $returning) {
"<a href='password.php3?email=$formfields[usr_email]'>".
"forgotten your username.</a>", 1);
}
if (! $forwikionly) {
if (isset($formfields[usr_URL]) &&
strcmp($formfields[usr_URL], "") &&
strcmp($formfields[usr_URL], $HTTPTAG) &&
......@@ -518,6 +621,7 @@ if (! $returning) {
elseif (!TBvalid_phone($formfields[usr_phone])) {
$errors["Phone #"] = TBFieldErrorString();
}
}
if (!isset($formfields[password1]) ||
strcmp($formfields[password1], "") == 0) {
$errors["Password"] = "Missing Field";
......@@ -536,8 +640,8 @@ if (! $returning) {
$errors["Password"] = "$checkerror";
}
}
if (!isset($formfields[pid]) ||
strcmp($formfields[pid], "") == 0) {
if (!$forwikionly && (!isset($formfields[pid]) ||
strcmp($formfields[pid], "") == 0)) {
$errors["Project Name"] = "Missing Field";
}
......@@ -552,18 +656,32 @@ if (count($errors)) {
#
if (!$returning) {
$joining_uid = $formfields[joining_uid];
$usr_title = addslashes($formfields[usr_title]);
$usr_name = addslashes($formfields[usr_name]);
$usr_affil = addslashes($formfields[usr_affil]);
$usr_email = $formfields[usr_email];
$password1 = $formfields[password1];
$password2 = $formfields[password2];
$wikiname = ($WIKISUPPORT ? $formfields[wikiname] : "");
if (!$forwikionly) {
$usr_affil = addslashes($formfields[usr_affil]);
$usr_title = addslashes($formfields[usr_title]);
$usr_addr = addslashes($formfields[usr_addr]);
$usr_city = addslashes($formfields[usr_city]);
$usr_state = addslashes($formfields[usr_state]);
$usr_zip = addslashes($formfields[usr_zip]);
$usr_country = addslashes($formfields[usr_country]);
$usr_phone = $formfields[usr_phone];
$password1 = $formfields[password1];
$password2 = $formfields[password2];
}
else {
$usr_affil = "";
$usr_title = "";
$usr_addr = "";
$usr_city = "";
$usr_state = "";
$usr_zip = "";
$usr_country = "";
$usr_phone = "";
}
if (! isset($formfields[usr_URL]) ||
strcmp($formfields[usr_URL], "") == 0 ||
......@@ -657,14 +775,16 @@ else {
$gid = $pid;
}
if (!TBvalid_pid($pid) || !TBValidProject($pid)) {
if (!$forwikionly) {
if (!TBvalid_pid($pid) || !TBValidProject($pid)) {
$errors["Project Name"] = "Invalid Project Name";
}
elseif (!TBvalid_gid($gid) || !TBValidGroup($pid, $gid)) {
}
elseif (!TBvalid_gid($gid) || !TBValidGroup($pid, $gid)) {
$errors["Group Name"] = "Invalid Group Name";
}
elseif (TBGroupMember($joining_uid, $pid, $gid, $approved)) {
}
elseif (TBGroupMember($joining_uid, $pid, $gid, $approved)) {
$errors["Membership"] = "You are already a member";
}
}
#
......@@ -702,14 +822,14 @@ if (! $returning) {
"(uid,usr_created,usr_expires,usr_name,usr_email,usr_addr,".
" usr_addr2,usr_city,usr_state,usr_zip,usr_country, ".
" usr_URL,usr_phone,usr_shell,usr_title,usr_affil,usr_pswd,unix_uid,".
" status,pswd_expires,usr_modified) ".
" status,pswd_expires,usr_modified,wikionly,wikiname) ".
"VALUES ('$joining_uid', now(), '$usr_expires', '$usr_name', ".
"'$usr_email', ".
"'$usr_addr', '$usr_addr2', '$usr_city', '$usr_state', '$usr_zip', ".
"'$usr_country', ".
"'$usr_URL', '$usr_phone', 'tcsh', '$usr_title', '$usr_affil', ".
"'$encoding', NULL, 'newuser', ".
"date_add(now(), interval 1 year), now())");
"date_add(now(), interval 1 year), now(), $forwikionly, '$wikiname')");
DBQueryFatal("INSERT INTO user_stats (uid) VALUES ('$joining_uid')");
......@@ -724,11 +844,17 @@ if (! $returning) {
"\n".
" ${TBBASE}/login.php3?vuid=$joining_uid&key=$key\n".
"\n".
($forwikionly ?
"Once you have verified your account, you will be able to access\n".
"the Wiki. You MUST verify your account first!"
:
"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".
"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".
"user account.") .
"\n\n".
"Thanks,\n".
"Testbed Operations\n",
"From: $TBMAIL_APPROVAL\n".
......@@ -736,6 +862,14 @@ if (! $returning) {
"Errors-To: $TBMAIL_WWW");
}
#
# For wikionly registration, we are done.
#
if ($forwikionly) {
header("Location: wikiregister.php3?finished=1");
exit();
}
#
# Add to the group, but with trust=none. The project/group leader will have
# to upgrade the trust level, making the new user real.
......@@ -814,5 +948,3 @@ if ($returning) {
# See above for conclusion.
#
header("Location: joinproject.php3?finished=1");
?>
......@@ -357,11 +357,19 @@ function WRITESIDEBAR() {
WRITESIDEBARBUTTON("Change Your Password",
$TBBASE, "moduserinfo.php3");
}
elseif ($login_status & CHECKLOGIN_WEBONLY) {
elseif ($login_status & CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY) {
WRITESIDEBARBUTTON("My Emulab",
$TBBASE,
"showuser.php3?target_uid=$login_uid");
if ($WIKISUPPORT && $CHECKLOGIN_WIKINAME != "") {
$wikiname = $CHECKLOGIN_WIKINAME;
WRITESIDEBARBUTTON_ABSCOOL("My Wikis",
"${WIKIURL}/Main/$wikiname",
"${WIKIURL}/Main/$wikiname");
}
WRITESIDEBARBUTTON("Update User Information",
$TBBASE, "moduserinfo.php3");
......
......@@ -19,7 +19,8 @@ include("showstuff.php3");
#
$uid = GETLOGIN();
LOGGEDINORDIE($uid,
CHECKLOGIN_USERSTATUS|CHECKLOGIN_PSWDEXPIRED|CHECKLOGIN_WEBONLY);
CHECKLOGIN_USERSTATUS|CHECKLOGIN_PSWDEXPIRED|
CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
$isadmin = ISADMIN($uid);
......@@ -29,13 +30,16 @@ $shelllist = array( 'tcsh', 'bash', 'csh', 'sh' );
# used if db slot for user is NULL (should not happen.)
$defaultshell = 'tcsh';
# See below.
$wikionly = 0;
#
# Spit the form out using the array of data and error strings (if any).
#
function SPITFORM($formfields, $errors)
{
global $TBDB_UIDLEN, $TBDB_PIDLEN, $TBDB_GIDLEN, $isadmin;
global $target_uid;
global $target_uid, $wikionly;
global $shelllist, $defaultshell;
#
......@@ -66,10 +70,13 @@ function SPITFORM($formfields, $errors)
echo "</table><br>\n";
}
# For indicating that fields are optional or not.
$optfield = ($wikionly ? "" : "*");
echo "<table align=center border=1>
<tr>
<td align=center colspan=3>
Fields marked with * are required.
<b>Fields marked with * are required.</b>
</td>
</tr>\n
......@@ -107,7 +114,7 @@ function SPITFORM($formfields, $errors)
# Title/Position:
#
echo "<tr>
<td colspan=2>*Title/Position:</td>
<td colspan=2>${optfield}Title/Position:</td>
<td class=left>
<input type=text
name=\"formfields[usr_title]\"
......@@ -120,7 +127,7 @@ function SPITFORM($formfields, $errors)
# Affiliation:
#
echo "<tr>
<td colspan=2>*Institutional<br>Affiliation:</td>
<td colspan=2>${optfield}Institutional<br>Affiliation:</td>
<td class=left>
<input type=text
name=\"formfields[usr_affil]\"
......@@ -146,7 +153,7 @@ function SPITFORM($formfields, $errors)
# Email:
#
echo "<tr>
<td colspan=2>*Email Address[<b>1</b>]:</td>
<td colspan=2>Email Address[<b>1</b>]:</td>
<td class=left> ";
if ($isadmin)
echo " <input type=text ";
......@@ -167,7 +174,10 @@ function SPITFORM($formfields, $errors)
$formfields[usr_country] = "USA";
}
echo "<tr><td colspan=3>*Address:<br /><center>
#
# Postal Address
#
echo "<tr><td colspan=3>${optfield}Address:<br /><center>
<table>
<tr><td>Line 1</td><td colspan=3>
<input type=text
......@@ -201,10 +211,6 @@ function SPITFORM($formfields, $errors)
size=15></td></tr>
</table></center></td></tr>";
#
# Default Group
#
# Default Shell
echo "<tr><td colspan=2>Shell:</td>
<td class=left>";
......@@ -225,7 +231,7 @@ function SPITFORM($formfields, $errors)
# Phone
#
echo "<tr>
<td colspan=2>*Phone #:</td>
<td colspan=2>${optfield}Phone #:</td>
<td class=left>
<input type=text
name=\"formfields[usr_phone]\"
......@@ -238,6 +244,7 @@ function SPITFORM($formfields, $errors)
# Password. Note that we do not resend the password. User
# must retype on error.
#
echo "<tr></tr>\n";
echo "<tr>
<td colspan=2>Password[<b>1</b>]:</td>
<td class=left>
......@@ -254,14 +261,16 @@ function SPITFORM($formfields, $errors)
size=8></td>
</tr>\n";
if (!$wikionly) {
#
# Windows Password. Initial random default is based on the Unix
# password hash.
#
# A separate password is kept for experiment nodes running Windows.
# It is presented behind-the-scenes to rdesktop and Samba by our Web
# interface, but you may still need to type it. The default password
# is randomly generated. You may change it to something easier to
# remember.
# It is presented behind-the-scenes to rdesktop and Samba by our
# Web# interface, but you may still need to type it.
# The default password is randomly generated.
# You may change it to something easier to remember.
#
echo "<tr>
<td colspan=2>Windows Password[<b>1,4</b>]:</td>
......@@ -281,7 +290,8 @@ function SPITFORM($formfields, $errors)
</tr>\n";
#
# Planetlab bit. This should really be a drop down menu of the choices.
# Planetlab bit. This should really be a drop down menu of the
# choices.
#
if ($formfields[user_interface] == TBDB_USER_INTERFACE_PLAB) {
$checked = "checked";
......@@ -298,6 +308,7 @@ function SPITFORM($formfields, $errors)
$checked