Commit 9310dedb authored by Leigh Stoller's avatar Leigh Stoller

Implement a cross machine login so that user is automatically logged

into the Wiki when clicking on the My Wiki's link. Works like this:

* The My Wiki's link points to new page, gotowiki.php3, on boss.

* The gotowiki page looks for a new cookie in the user's browser
  which holds a key (the usual random data run through md5).

* If the key does not exist, generate it and store it in the user
  browser (expires when browser is closed or emulab login times out).
  Also invoke backend script wikixlogin, which will send the key over
  to the wiki server (via ssh), which will write the key into a file
  named by the user account.

* The user's browser is redirected to the wiki server's login script
  (twiki/bin/newlogon), but instead of username and password, we send
  over username and key (as well as redurl= parameter which is the
  page on the wiki server to redirect to later).

* The new login script looks for this case, and opens the file named
  by the user and compares the key it gets with what is in the file.
  If they match, the user login succeeds and the browser is once again
  redirected, but this time to the page it wants on the wiki server.
  If the key does not match, the browser is redirected to the login
  page (so user can enter username password normally). The redurl
  parameter is passed along as well.

* Subsequent clicks on My Wiki's will not need to invoke the backend
  script, since the cookie will be in the browser.
parent ab2e986d
......@@ -13,6 +13,7 @@ include $(OBJDIR)/Makeconf
SBIN_SCRIPTS = addwikiuser addwikiproj wikisetup delwikiuser \
setwikigroups
LIBEXEC_SCRIPTS = wikixlogin
CTRL_SBIN_SCRIPTS = wikiproxy
CTRL_LIB_FILES = usertemplate webhometemplate
......@@ -21,11 +22,13 @@ CTRL_LIB_FILES = usertemplate webhometemplate
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
#
all: $(SBIN_SCRIPTS) $(CTRL_SBIN_SCRIPTS) $(CTRL_LIB_FILES)
all: $(SBIN_SCRIPTS) $(CTRL_SBIN_SCRIPTS) $(CTRL_LIB_FILES) \
$(LIBEXEC_SCRIPTS)
include $(TESTBED_SRCDIR)/GNUmakerules
install: $(addprefix $(INSTALL_SBINDIR)/, $(SBIN_SCRIPTS)) \
$(addprefix $(INSTALL_LIBEXECDIR)/, $(LIBEXEC_SCRIPTS)) \
$(addprefix $(INSTALL_DIR)/opsdir/sbin/, $(CTRL_SBIN_SCRIPTS)) \
$(addprefix $(INSTALL_DIR)/opsdir/lib/wiki/, $(CTRL_LIB_FILES))
......@@ -42,6 +45,8 @@ post-install:
chmod u+s $(INSTALL_SBINDIR)/addwikiproj
chown root $(INSTALL_SBINDIR)/setwikigroups
chmod u+s $(INSTALL_SBINDIR)/setwikigroups
chown root $(INSTALL_LIBEXECDIR)/wikixlogin
chmod u+s $(INSTALL_LIBEXECDIR)/wikixlogin
#
# Control node installation (okay, plastic)
......
......@@ -24,9 +24,18 @@ use TWiki;
use TWiki::Plugins::SessionPlugin;
my $oopsurl = "oopsloginfail";
my $CREDDIR = "/var/db/cgisess";
$query= new CGI;
sub myerror($)
{
my ($msg) = @_;
my $url = &TWiki::getOopsUrl(undef, "", $oopsurl, $msg);
TWiki::redirect($query, $url);
}
&main();
sub main
......@@ -34,17 +43,61 @@ sub main
my $username = $query->param('username');
my $password = $query->param('password');
my $redurl = $query->param('redurl');
my $bosscred = $query->param('bosscred');
chomp($username);
chomp($password);
#
# If bosscred provided, boss is trying to autologin the user using
# a key that it sent across via a backend script and stashed in the
# cookie dir. Find that file, compare the keys and if the key is not
# too terribly old, give the user the nod.
#
if (defined($bosscred)) {
if (!defined($username) || $username eq "") {
myerror("Missing username argument");
return;
}
my $file = "${CREDDIR}/$username";
if (! -e $file) {
myerror("Cred file does not exist!");
return;
}
if (!open(COK, $file)) {
myerror("Cannot open cred file!");
return;
}
my $cred = <COK>;
my $stamp = <COK>;
close(COK);
# Compare credentials.
if (defined($cred)) {
chomp($cred);
if ($cred eq $bosscred) {
goto accepted;
}
}
# Does not match. Redirect to login page.
dologon:
my $url = &TWiki::getViewUrl("TWiki", "DoLogin");
$url .= "?username=${username}";
$url .= "&redurl=${redurl}"
if (defined($redurl) && $redurl ne "");
TWiki::redirect($query, $url);
return;
}
#
# Normal login.
#
if (! ($username && $password)) {
my $url = &TWiki::getOopsUrl(undef, "", $oopsurl,
"Missing arguments (username or password)");
TWiki::redirect( $query, $url );
myerror("Missing arguments (username or password)");
return;
}
chomp($username);
chomp($password);
#
# Suck out the password entry.
......@@ -63,9 +116,7 @@ sub main
close(HTP);
if (!defined($pwentry)) {
my $url = &TWiki::getOopsUrl(undef, "", $oopsurl,
"No such user: '$username'");
TWiki::redirect( $query, $url );
myerror("No such user: '$username'");
return;
}
......@@ -78,15 +129,14 @@ sub main
my $str = crypt($password, $encryptedpasswd);
if ($str ne $encryptedpasswd) {
my $url = &TWiki::getOopsUrl(undef, "", $oopsurl,
"Incorrect Password");
TWiki::redirect( $query, $url );
myerror("Incorrect Password");
return;
}
# This causes the query object to suddenly have a remote_user() value.
# SessionPlugin uses that ...
$ENV{REMOTE_USER} = $username;
accepted:
$ENV{REMOTE_USER} = $username;
#
# Stuff we need to pass down. Note that I am not bothering with the
......
......@@ -40,6 +40,7 @@ my $WIKIGROUPDIR = "$WIKIDATADIR/Main";
my $WIKIARCHIVE = "$WIKIDATADIR/_archive";
my $WIKIPASSWD = "$WIKIDIR/data/.htpasswd";
my $USERMAPDB = "$WIKIDIR/data/.usermap";
my $COOKIEDIR = "/var/db/cgisess";
my $WIKIUSER = "nobody";
my $WIKIGROUP = "nobody";
my $CI = "ci";
......@@ -99,6 +100,9 @@ elsif ($action eq "addproject") {
elsif ($action eq "setgroups") {
exit(SetWikiGroups(@ARGV));
}
elsif ($action eq "xlogin") {
exit(WikixLogin(@ARGV));
}
else {
die("*** $0:\n".
" Do not know what to do with '$action'!\n");
......@@ -724,6 +728,31 @@ sub CI($$) {
}
return $? >> 8;
}
#
# Backdoor Login
#
sub WikixLogin(@)
{
usage()
if (@_ != 2);
my ($user, $secretkey) = @_;
#
# Create a little file that holds the secret key, named by the user.
# The TWiki login script will check for the existence of this file,
# and use the key inside it to match against the key provided by the
# client browser.
#
open(KEY, ">${COOKIEDIR}/$user") or
fatal("Could not open ${COOKIEDIR}/$user for writing!");
print KEY "$secretkey\n";
print KEY time() . "\n";
close(KEY);
return 0;
}
sub fatal($)
{
......
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
use Fcntl ':flock';
#
# Add a user to the wiki on ops. Also allow update of password.
#
sub usage()
{
print STDOUT "Usage: wikixlogin <uid> <key>\n";
exit(-1);
}
my $optlist = "d";
my $debug = 0;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $CONTROL = "@USERNODE@";
my $BOSSNODE = "@BOSSNODE@";
my $WIKISUPPORT = @WIKISUPPORT@;
my $SSH = "$TB/bin/sshtb";
my $WIKIPROXY = "$TB/sbin/wikiproxy";
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/usr/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
# Load the Testbed support stuff.
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
#
# We do not want to run this script unless its the real version.
#
if ($EUID != 0) {
die("*** $0:\n".
" Must be setuid! Maybe its a development version?\n");
}
#
# This script is setuid, so please do not run it as root. Hard to track
# what has happened.
#
if ($UID == 0) {
die("*** $0:\n".
" Please do not run this as root! Its already setuid!\n");
}
#
# If no wiki support, just exit.
#
if (! $WIKISUPPORT) {
print "WIKI support is not enabled. Exit ...\n";
exit(0);
}
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"d"})) {
$debug = 1;
}
if (@ARGV != 2) {
usage();
}
my $user = $ARGV[0];
my $key = $ARGV[1];
#
# Untaint args.
#
if ($user =~ /^([-\w]+)$/) {
$user = $1;
}
else {
die("Bad data in user: $user.");
}
if ($key =~ /^([\w]+)$/) {
$key = $1;
}
else {
fatal("Bad data in secretkey!");
}
#
# For ssh.
#
$UID = $EUID;
if ($CONTROL ne $BOSSNODE) {
if (system("$SSH -host $CONTROL $WIKIPROXY xlogin $user '$key'")) {
fatal("$WIKIPROXY failed on $CONTROL!");
}
}
exit(0);
sub fatal($)
{
my($mesg) = $_[0];
die("*** $0:\n".
" $mesg\n");
}
......@@ -16,7 +16,8 @@ $TBWWW = "@TBWWW@";
$THISHOMEBASE = "@THISHOMEBASE@";
$ELABINELAB = @ELABINELAB@;
$WIKISUPPORT = @WIKISUPPORT@;
$WIKIURL = "https://${USERNODE}/twiki/bin/view";
$WIKIURL = "https://${USERNODE}/twiki/bin/newlogon";
$WIKICOOKIENAME = "WikiCookie";
$TBMAILADDR_OPS = "@TBOPSEMAIL_NOSLASH@";
$TBMAILADDR_WWW = "@TBWWWEMAIL_NOSLASH@";
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
if (!$WIKISUPPORT) {
header("Location: index.php3");
return;
}
# No Pageheader since we spit out a redirection below.
$uid = GETLOGIN();
LOGGEDINORDIE($uid, CHECKLOGIN_USERSTATUS|
CHECKLOGIN_WEBONLY|CHECKLOGIN_WIKIONLY);
#
# The page to zap to on the other side
#
if (isset($redurl) && $redurl == "") {
unset($redurl);
}
#
# Look for our wikicookie. If the browser has it, then there is nothing
# more to do; just redirect the user over to the wiki.
#
if (isset($_COOKIE[$WIKICOOKIENAME])) {
$wikihash = $_COOKIE[$WIKICOOKIENAME];
header("Location: ${WIKIURL}?username=${uid}&bosscred=${wikihash}" .
(isset($redurl) ? "&redurl=${redurl}" : ""));
return;
}
#
# Generate a cookie. Send it over to the wiki server and stash it into
# the users browser for subsequent requests (until logout).
#
$wikihash = GENHASH();
SUEXEC("nobody", "nobody", "wikixlogin $uid $wikihash", SUEXEC_ACTION_DIE);
setcookie($WIKICOOKIENAME, $wikihash, 0, "/", $TBAUTHDOMAIN, $TBSECURECOOKIES);
header("Location: ${WIKIURL}?username=${uid}&bosscred=${wikihash}" .
(isset($redurl) ? "&redurl=${redurl}" : ""));
?>
......@@ -366,8 +366,8 @@ function WRITESIDEBAR() {
$wikiname = $CHECKLOGIN_WIKINAME;
WRITESIDEBARBUTTON_ABSCOOL("My Wikis",
"${WIKIURL}/Main/$wikiname",
"${WIKIURL}/Main/$wikiname");
"gotowiki.php3?redurl=Main/$wikiname",
"gotowiki.php3?redurl=Main/$wikiname");
}
WRITESIDEBARBUTTON("Update User Information",
......@@ -391,8 +391,8 @@ function WRITESIDEBAR() {
$wikiname = $CHECKLOGIN_WIKINAME;
WRITESIDEBARBUTTON_ABSCOOL("My Wikis",
"${WIKIURL}/Main/$wikiname",
"${WIKIURL}/Main/$wikiname");
"gotowiki.php3?redurl=Main/$wikiname",
"gotowiki.php3?redurl=Main/$wikiname");
}
# Since a user can be a member of more than one project,
......
......@@ -14,7 +14,7 @@
# A project
#
function SHOWPROJECT($pid, $thisuid) {
global $WIKISUPPORT, $WIKIURL;
global $WIKISUPPORT;
$query_result =
DBQueryFatal("select p.*,g.wikiname from projects as p ".
......@@ -92,7 +92,7 @@ function SHOWPROJECT($pid, $thisuid) {
</tr>\n";
if ($WIKISUPPORT && isset($wikiname)) {
$wikiurl = "${WIKIURL}/$wikiname/WebHome";
$wikiurl = "gotowiki.php3?redurl=$wikiname/WebHome";
echo "<tr>
<td>Project Wiki:</td>
......@@ -383,7 +383,7 @@ function SHOWGROUPMEMBERSHIP($uid) {
# A User
#
function SHOWUSER($uid) {
global $WIKISUPPORT, $WIKIURL;
global $WIKISUPPORT;
$userinfo_result =
DBQueryFatal("SELECT * from users where uid='$uid'");
......@@ -468,7 +468,7 @@ function SHOWUSER($uid) {
</tr>\n";
if ($WIKISUPPORT && isset($wikiname)) {
$wikiurl = "${WIKIURL}/Main/$wikiname";
$wikiurl = "gotowiki.php3?redurl=Main/$wikiname";
echo "<tr>
<td>Emulab Wiki Page:</td>
......
......@@ -530,6 +530,7 @@ function DOLOGIN($token, $password, $adminmode = 0) {
global $TBAUTHCOOKIE, $TBAUTHDOMAIN, $TBAUTHTIMEOUT;
global $TBNAMECOOKIE, $TBLOGINCOOKIE, $TBSECURECOOKIES;
global $TBMAIL_OPS, $TBMAIL_AUDIT, $TBMAIL_WWW;
global $WIKISUPPORT, $WIKICOOKIENAME;
# Caller makes these checks too.
if ((!TBvalid_uid($token) && !TBvalid_email($token)) ||
......@@ -785,6 +786,7 @@ function VERIFYPASSWD($uid, $password) {
#
function DOLOGOUT($uid) {
global $CHECKLOGIN_STATUS, $TBAUTHCOOKIE, $TBLOGINCOOKIE, $TBAUTHDOMAIN;
global $WIKISUPPORT, $WIKICOOKIENAME;
# Pedantic check.
if (!TBvalid_uid($uid)) {
......@@ -811,6 +813,9 @@ function DOLOGOUT($uid) {
#
setcookie($TBAUTHCOOKIE, "", $timeout, "/", $TBAUTHDOMAIN, 0);
setcookie($TBLOGINCOOKIE, "", $timeout, "/", $TBAUTHDOMAIN, 0);
if ($WIKISUPPORT) {
setcookie($WIKICOOKIENAME, "", $timeout, "/", $TBAUTHDOMAIN, 0);
}
return 0;
}
......
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