Commit 8def7e94 authored by Leigh Stoller's avatar Leigh Stoller

Changes to allow new users to request their encrypted SSL certificate

on the join/start project pages. At the moment this is conditional
under the PROTOGENI flag, since users on non-protogeni sites rarely
need an encrypted SSL certificate. The initial passphrase has to be
store someplace since we cannot built the certificate until the user
is approved, so put it into the users table, and delete when the first
certificate is built (at approval).
parent 939ec3af
......@@ -150,6 +150,7 @@ my %optional = ("uid" => "uid",
"URL" => "usr_URL",
"shell" => "usr_shell",
"password" => undef,
"passphrase" => "initial_passphrase",
"pubkey" => undef,
"pubkeys" => undef);
......@@ -318,6 +319,36 @@ else {
$newuser_args{'usr_pswd'} = crypt($pswd, "\$1\$" . substr(time(), 0, 8));
}
#
# Check the passphrase if supplied.
#
if (exists($xmlparse->{'attribute'}->{'passphrase'}) &&
$xmlparse->{'attribute'}->{'passphrase'}->{'value'} != "") {
my $passphrase = $xmlparse->{'attribute'}->{'passphrase'}->{'value'};
my $checkpass_args = escapeshellarg($passphrase);
$checkpass_args .= " " .
(exists($newuser_args{'uid'}) ? $newuser_args{'uid'} : "ignored");
$checkpass_args .= escapeshellarg($newuser_args{'usr_name'} . ":" .
$newuser_args{'usr_email'});
my $pwokay = `$checkpass $checkpass_args`;
if ($?) {
chomp($pwokay);
if (! ($pwokay =~ /^ok$/)) {
UserError("$pwokay");
}
fatal("Checkpass failed with $?");
}
$newuser_args{'initial_passphrase'} = $passphrase;
if (! (exists($xmlparse->{'attribute'}->{'pubkey'}) ||
exists($xmlparse->{'pubkeys'}))) {
UserError("Must provide SSH pubkey when requesting SSL Certificate")
}
}
#
# Do a check on the pubkey if supplied. The safest thing to do is generate
# a temporary file and pass that to addpubkey to check.
......
......@@ -450,6 +450,21 @@ sub AddUser()
}
# Generate the SSL cert for the user.
system("$MKUSERCERT $user");
#
# If the user requested an initial encrypted SSL certificate, create
# that too. Need to delete the initial_passphrase slot though, so that
# we do not try to recreate it at some future time.
#
if (defined($target_user->initial_passphrase())) {
my $pphrase = User::escapeshellarg($target_user->initial_passphrase());
system("$MKUSERCERT -p '$pphrase' $user");
if ($?) {
fatal("Could not create initial encrypted SSL certificate");
}
$target_user->Update({'initial_passphrase' => undef});
}
if ($nocollabtools) {
$EUID = 0;
......
......@@ -874,6 +874,8 @@ sub SendJoinEmail($$)
my $usr_affil = $user->affil();
my $uid_idx = $user->uid_idx();
my $uid = $user->uid();
my $wanted_sslcert = (defined($user->initial_passphrase()) ?
"Yes" : "No");
# And leader info
my $leader = $self->GetLeader();
......@@ -909,6 +911,7 @@ sub SendJoinEmail($$)
"ZIP/Postal Code: $usr_zip\n".
"Country: $usr_country\n".
"Phone: $usr_phone\n".
"SSL Cert: $wanted_sslcert\n";
"\n".
"Please return to $TBWWW,\n".
"log in, select the 'New User Approval' page, and enter your\n".
......
......@@ -433,6 +433,8 @@ sub SendNewProjectEmail($;$)
my $wikiname = $leader->wikiname();
my $returning = $leader->status() ne $User::USERSTATUS_NEWUSER;
my $usr_returning = ($returning ? "Yes" : "No");
my $wanted_sslcert = (defined($leader->initial_passphrase()) ?
"Yes" : "No");
my $proj_desc = $self->description();
my $proj_URL = $self->URL();
my $proj_funders = $self->funders();
......@@ -483,6 +485,7 @@ sub SendNewProjectEmail($;$)
"ZIP/Postal Code: $usr_zip\n".
"Country: $usr_country\n".
"Phone: $usr_phone\n".
"SSL Cert: $wanted_sslcert\n";
"Members: $proj_members\n".
"PCs: $proj_pcs\n".
"Planetlab PCs: $proj_plabpcs\n".
......
......@@ -186,6 +186,7 @@ sub chpasswd_expires($) { return field($_[0], "chpasswd_expires"); }
sub wikiname($) { return field($_[0], "wikiname"); }
sub wikionly($) { return field($_[0], "wikionly"); }
sub mailman_password($) { return field($_[0], "mailman_password"); }
sub initial_passphrase($) { return field($_[0], "initial_passphrase"); }
sub active($) { return ($_[0]->status() eq "active" ? 1 : 0); };
sub newuser($) { return ($_[0]->status() eq "newuser" ? 1 : 0); };
sub archived($) { return ($_[0]->status() eq "archived" ? 1 : 0); };
......@@ -998,11 +999,18 @@ sub Update($$)
if (! ref($self));
my $uid_idx = $self->uid_idx();
my @sets = ();
my $query = "update users set usr_modified=now(), ".
join(",", map("$_=" . DBQuoteSpecial($argref->{$_}), keys(%{$argref})));
foreach my $key (keys(%{$argref})) {
my $val = $argref->{$key};
$query .= " where uid_idx='$uid_idx'";
# Treat NULL special.
push (@sets, "${key}=" . ($val eq "NULL" ?
"NULL" : DBQuoteSpecial($val)));
}
my $query = "update users set usr_modified=now(), " . join(",", @sets) .
" where uid_idx='$uid_idx'";
return -1
if (! DBQueryWarn($query));
......
......@@ -4031,6 +4031,7 @@ CREATE TABLE `users` (
`manager_urn` varchar(128) default NULL,
`default_project` mediumint(8) unsigned default NULL,
`nocollabtools` tinyint(1) default '0',
`initial_passphrase` varchar(128) default NULL,
PRIMARY KEY (`uid_idx`),
KEY `unix_uid` (`unix_uid`),
KEY `status` (`status`),
......
......@@ -787,6 +787,7 @@ REPLACE INTO table_regex VALUES ('users','w_password1','text','redirect','defaul
REPLACE INTO table_regex VALUES ('users','w_password2','text','redirect','default:tinytext',0,0,NULL);
REPLACE INTO table_regex VALUES ('users','user_interface','text','regex','^(emulab|plab)$',0,0,NULL);
REPLACE INTO table_regex VALUES ('users','notes','text','redirect','default:fulltext',0,65535,NULL);
REPLACE INTO table_regex VALUES ('users','initial_passphrase','text','redirect','default:tinytext',0,128,NULL);
REPLACE INTO table_regex VALUES ('virt_agents','pid','text','redirect','projects:pid',0,0,NULL);
REPLACE INTO table_regex VALUES ('virt_agents','eid','text','redirect','experiments:eid',0,0,NULL);
......
......@@ -103,6 +103,7 @@ INSERT INTO sitevariables VALUES ('images/frisbee/maxrate_usr',NULL,'54000000','
INSERT INTO sitevariables VALUES ('general/idlepower_enable',NULL,'0','Enable idle power down to conserve electricity',0);
INSERT INTO sitevariables VALUES ('general/idlepower_idletime',NULL,'3600','Maximum number of seconds idle before a node is powered down to conserve electricity',0);
INSERT INTO sitevariables VALUES ('general/autoswap_max',NULL,'120','Maximum number of hours for the experiment autoswap limit.',0);
INSERT INTO sitevariables VALUES ('protogeni/show_sslcertbox','1','1','When set, users see option on join/start project pages to create SSL certificate.',0);
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
......
#
# Add initial_passphrase slot to users table.
#
use strict;
use libdb;
my $impotent = 0;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
if (!DBSlotExists("users", "initial_passphrase")) {
DBQueryFatal("alter table users add ".
" `initial_passphrase` varchar(128) default NULL");
}
DBQueryFatal("REPLACE INTO table_regex VALUES ".
" ('users','initial_passphrase','text','redirect', ".
" 'default:tinytext',0,128,NULL)");
DBQueryFatal("INSERT INTO sitevariables VALUES ".
" ('protogeni/show_sslcertbox','1','1', ".
" 'When set, users see option on join/start project pages ".
"to create SSL certificate.',0)")
if (!TBSiteVarExists("protogeni/show_sslcertbox"));
return 0;
}
......@@ -16,6 +16,9 @@ if (isset($forwikionly) && $forwikionly == True) {
$old_forwikionly = False;
}
# Need this below;
$show_sslcertbox = TBGetSiteVar("protogeni/show_sslcertbox");
#
# No PAGEHEADER since we spit out a Location header later. See below.
#
......@@ -81,6 +84,7 @@ function SPITFORM($formfields, $returning, $errors)
global $ACCOUNTWARNING, $EMAILWARNING;
global $WIKISUPPORT, $forwikionly, $WIKIHOME, $USERSELECTUIDS;
global $WIKIDOCURL;
global $PROTOGENI, $show_sslcertbox;
if ($forwikionly)
PAGEHEADER("Wiki Registration");
......@@ -160,8 +164,8 @@ function SPITFORM($formfields, $returning, $errors)
echo "<table align=center border=1>
<tr>
<td align=center colspan=3>
Fields marked with * are required.
<td align=center colspan=3><font size=-1>
Fields marked with * are required.</font>
</td>
</tr>\n
......@@ -381,7 +385,39 @@ function SPITFORM($formfields, $returning, $errors)
value=\"" . $formfields["password2"] . "\"
size=8></td>
</tr>\n";
#
# Geni Passphrase.
#
if ($PROTOGENI && $show_sslcertbox) {
echo "<tr></tr><tr>
<th class=center colspan=3>Geni Account<br>
<a href='http://users.emulab.net/trac/emulab/wiki/GeniBlurb'
target=_blank><font size=-2>what's this?</font></a></td>
</tr>\n";
echo "<tr>
<td colspan=2>Geni SSL Pass Phrase[<b>3</b>]:</td>
<td class=left>
<input type=password
name=\"formfields[passphrase1]\"
value=\"" . $formfields["passphrase1"] . "\"
size=32></td>
</tr>\n";
echo "<tr>
<td colspan=2>Retype Geni Pass Phrase:</td>
<td class=left>
<input type=password
name=\"formfields[passphrase2]\"
value=\"" . $formfields["passphrase2"] . "\"
size=32></td>
</tr>\n";
}
}
echo "<tr></tr><tr>
<th class=center colspan=3>Project Info</td>
</tr>\n";
if (! $forwikionly) {
#
......@@ -430,7 +466,7 @@ function SPITFORM($formfields, $returning, $errors)
if (!$returning && !$forwikionly) {
echo "<li> If you want us to use your existing ssh public key,
then please specify the path to your
your identity.pub file. <font color=red>NOTE:</font>
identity.pub file. <font color=red>NOTE:</font>
We use the <a href=http://www.openssh.org target='_blank'>OpenSSH</a>
key format,
which has a slightly different protocol 2 public key format
......@@ -439,6 +475,12 @@ function SPITFORM($formfields, $returning, $errors)
use one of these commercial vendors, then please
upload the public key file and we will convert it
for you.";
if ($PROTOGENI && $show_sslcertbox) {
echo "<li>";
echo "Pick a good pass phrase! They can be (much) longer than
Unix passwords; 10 to 30 character phrases are good,
and may include spaces and punctuation.";
}
}
echo "</ol>
</blockquote></blockquote>
......@@ -508,6 +550,8 @@ if (! isset($submit)) {
$defaults["usr_affil_abbrev"] = "";
$defaults["password1"] = "";
$defaults["password2"] = "";
$defaults["passphrase1"] = "";
$defaults["passphrase2"] = "";
$defaults["wikiname"] = "";
$defaults["usr_URL"] = "$HTTPTAG";
$defaults["usr_country"] = "USA";
......@@ -685,6 +729,29 @@ if (! $returning) {
$formfields["usr_email"], $checkerror)) {
$errors["Password"] = "$checkerror";
}
if ($PROTOGENI && $show_sslcertbox &&
isset($formfields["passphrase1"]) && $formfields["passphrase1"] != "") {
if (!isset($formfields["passphrase2"]) ||
$formfields["passphrase2"] == "") {
$errors["Confirm Pass Phrase"] = "Missing Field";
}
elseif ($formfields["passphrase1"] != $formfields["passphrase2"]) {
$errors["Confirm Pass Phrase"] = "Does not match Pass Phrase";
}
elseif (! CHECKPASSWORD(($USERSELECTUIDS ?
$formfields["joining_uid"] : "ignored"),
$formfields["passphrase1"],
$formfields["usr_name"],
$formfields["usr_email"], $checkerror)) {
$errors["Pass Phrase"] = "$checkerror";
}
if (! (isset($_FILES['usr_keyfile']) &&
$_FILES['usr_keyfile']['name'] != "" &&
$_FILES['usr_keyfile']['name'] != "none")) {
$errors["SSH Pub Key"] =
"You must provide an SSH pubkey to use Geni";
}
}
}
if (!$forwikionly) {
if (!isset($formfields["pid"]) || $formfields["pid"] == "") {
......@@ -800,6 +867,10 @@ if (! $returning) {
$args["pubkey"] = file_get_contents($localfile);
}
}
if ($PROTOGENI && $show_sslcertbox &&
isset($formfields["passphrase1"]) && $formfields["passphrase1"] != "") {
$args["passphrase"] = $formfields["passphrase1"];
}
if (! ($user = User::NewNewUser(($forwikionly ?
TBDB_NEWACCOUNT_WIKIONLY : 0),
$args,
......
......@@ -27,6 +27,9 @@ $optargs = OptionalPageArguments("submit", PAGEARG_STRING,
#
$FirstInitState = (TBGetFirstInitState() == "createproject");
# Need this below;
$show_sslcertbox = TBGetSiteVar("protogeni/show_sslcertbox");
#
# 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
......@@ -67,6 +70,7 @@ function SPITFORM($formfields, $returning, $errors)
global $ACCOUNTWARNING, $EMAILWARNING;
global $WIKISUPPORT, $WIKIHOME, $USERSELECTUIDS;
global $WIKIDOCURL, $TBMAINSITE;
global $PROTOGENI, $show_sslcertbox;
PAGEHEADER("Start a New Testbed Project");
......@@ -148,13 +152,11 @@ function SPITFORM($formfields, $returning, $errors)
}
</SCRIPT>\n";
echo "<table align=center border=1>
<tr>
<td align=center colspan=3>
Fields marked with * are required.
</td>
</tr>\n
echo "<div align=left>
<font color=red size=-2>Fields marked with * are required</font>
</div>\n";
echo "<table align=center border=1>
<form enctype=multipart/form-data name=myform
action=newproject.php3 method=post>\n";
......@@ -163,8 +165,8 @@ function SPITFORM($formfields, $returning, $errors)
# Start user information stuff. Presented for new users only.
#
echo "<tr>
<th colspan=3>
Project Head Information:&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp
<th colspan=3 class=center>
Project Head Information<br>
<font size=-2>
(Prospective project leaders please read our
<a href='$WIKIDOCURL/AdminPolicies' target='_blank'>
......@@ -373,12 +375,41 @@ function SPITFORM($formfields, $returning, $errors)
value=\"" . $formfields["password2"] . "\"
size=8></td>
</tr>\n";
#
# Geni Passphrase.
#
if ($PROTOGENI && $show_sslcertbox && !$FirstInitState) {
echo "<tr></tr><tr>
<th class=center colspan=3>Geni Account<br>
<a href='http://users.emulab.net/trac/emulab/wiki/GeniBlurb'
target=_blank><font size=-2>what's this?</font></a></th>
</tr>\n";
echo "<tr>
<td colspan=2>Geni SSL Pass Phrase[<b>4</b>]:</td>
<td class=left>
<input type=password
name=\"formfields[passphrase1]\"
value=\"" . $formfields["passphrase1"] . "\"
size=32></td>
</tr>\n";
echo "<tr>
<td colspan=2>Retype Geni Pass Phrase:</td>
<td class=left>
<input type=password
name=\"formfields[passphrase2]\"
value=\"" . $formfields["passphrase2"] . "\"
size=32></td>
</tr>\n";
}
}
#
# Project information
#
echo "<tr><th colspan=3>
echo "<tr></tr><tr><th colspan=3 class=center>
Project Information:
<!-- <em>(replace the example entries)</em> -->
</th>
......@@ -577,6 +608,12 @@ function SPITFORM($formfields, $returning, $errors)
use one of these commercial vendors, then please
upload the public key file and we will convert it
for you.\n";
if ($PROTOGENI && $show_sslcertbox && !$FirstInitState) {
echo "<li>";
echo "Pick a good pass phrase! They can be (much) longer than
Unix passwords; 10 to 30 character phrases are good,
and may include spaces and punctuation.";
}
}
echo "</ol>
</blockquote></blockquote></blockquote>
......@@ -631,6 +668,8 @@ if (! isset($submit)) {
$defaults["usr_phone"] = "";
$defaults["password1"] = "";
$defaults["password2"] = "";
$defaults["passphrase1"] = "";
$defaults["passphrase2"] = "";
$defaults["pid"] = "";
$defaults["proj_name"] = "";
......@@ -821,6 +860,29 @@ if (! $returning) {
$formfields["usr_email"], $checkerror)) {
$errors["Password"] = "$checkerror";
}
if ($PROTOGENI && $show_sslcertbox &&
isset($formfields["passphrase1"]) && $formfields["passphrase1"] != "") {
if (!isset($formfields["passphrase2"]) ||
$formfields["passphrase2"] == "") {
$errors["Confirm Pass Phrase"] = "Missing Field";
}
elseif ($formfields["passphrase1"] != $formfields["passphrase2"]) {
$errors["Confirm Pass Phrase"] = "Does not match Pass Phrase";
}
elseif (! CHECKPASSWORD(($USERSELECTUIDS ?
$formfields["proj_head_uid"] : "ignored"),
$formfields["passphrase1"],
$formfields["usr_name"],
$formfields["usr_email"], $checkerror)) {
$errors["Pass Phrase"] = "$checkerror";
}
if (! (isset($_FILES['usr_keyfile']) &&
$_FILES['usr_keyfile']['name'] != "" &&
$_FILES['usr_keyfile']['name'] != "none")) {
$errors["SSH Pub Key"] =
"You must provide an SSH pubkey to use Geni";
}
}
}
if (!isset($formfields["pid"]) ||
......@@ -957,6 +1019,10 @@ if (!$returning) {
$localfile = $_FILES['usr_keyfile']['tmp_name'];
$args["pubkey"] = file_get_contents($localfile);
}
if ($PROTOGENI && $show_sslcertbox &&
isset($formfields["passphrase1"]) && $formfields["passphrase1"] != "") {
$args["passphrase"] = $formfields["passphrase1"];
}
# Just collect the user XML args here and pass the file to NewNewProject.
# Underneath, newproj calls newuser with the XML file.
......
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2010 University of Utah and the Flux Group.
* Copyright (c) 2000-2011 University of Utah and the Flux Group.
* All rights reserved.
*/
......@@ -20,6 +20,11 @@ th {
text-align: left;
vertical-align: bottom;
}
th.center {
background-color: #E1EAEA;
text-align: center;
vertical-align: bottom;
}
caption {
padding-bottom: 4px;
}
......
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