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

A little auth module plugin I wrote to allow cross-domain login from

emulab to the protogeni wiki, but I use it for all of the wikis. The
basic idea is that the emulab backend inserts a hash value into the
cookie table in the trac DB on ops (via ssh). Then Emulab issues a
redirect over to the trac wiki, with the uid/hash values as arguments
to the xlogin URL. This hash is use-once; if it exists in the cookies
table, it is deleted and a new one generated by the underlying auth
module, and a cookie returned to the browser. The user is thus logged
in for all subsequent access.

Why? Cause emulab.net cannot insert auth cookies for protogeni.net, so
must let the auth module inside trac insert the cookie.
parent d1cfc9a4
#
# EMULAB-COPYRIGHT
# Copyright (c) 2008 University of Utah and the Flux Group.
# All rights reserved.
#
# A little auth module I wrote to allow cross-domain login from emulab
# to the protogeni wiki, but I use it for all of the wikis. The basic
# idea is that the emulab backend inserts a hash value into the cookie
# table in the trac DB on ops (via ssh). Then Emulab issues a redirect
# over to the trac wiki, with the uid/hash values as arguments to the
# xlogin URL. This hash is use-once; if it exists in the cookies table,
# it is deleted and a new one generated by the underlying auth module,
# and a cookie returned to the browser. The user is thus logged in for
# all subsequent access.
#
# Why? Cause emulab.net cannot insert auth cookies for protogeni.net, so
# must let the auth module inside trac insert the cookie.
#
import string
import re
from trac import perm, util
from trac.core import *
from trac.config import Option
from trac.web import auth
from trac.web.api import IAuthenticator
from trac.web.main import IRequestHandler
from trac.util.html import escape, html
def if_enabled(func):
def wrap(self, *args, **kwds):
if not self.enabled:
return None
return func(self, *args, **kwds)
return wrap
class EmulabAuthModule(auth.LoginModule):
def authenticate(self, req):
if req.method == 'GET' and req.path_info.startswith('/xlogin'):
req.environ['REMOTE_USER'] = self._remote_user(req)
pass
return auth.LoginModule.authenticate(self, req)
def match_request(self, req):
return re.match('/(xlogin|logout)', req.path_info)
authenticate = if_enabled(authenticate)
match_request = if_enabled(match_request)
def process_request(self, req):
if req.path_info.startswith('/xlogin') and req.authname == 'anonymous':
raise TracError(html("Authentication information not available."))
if req.path_info.startswith('/xlogin'):
if not req.remote_user:
req.redirect(self.env.abs_href())
return
auth.LoginModule._do_login(self, req)
req.redirect(self.env.abs_href())
pass
elif req.path_info.startswith('/logout'):
auth.LoginModule._do_logout(self, req)
self._redirect_back(req)
pass
def _remote_user(self, req):
user = req.args.get('user')
hash = req.args.get('hash')
if not user or not hash:
return None
#
# Here is where we check the hash against the auth_cookie table
# in the DB. There is no cookie yet since we have just come from
# another domain.
#
db = self.env.get_db_cnx()
cursor = db.cursor()
if self.check_ip:
cursor.execute("SELECT name FROM auth_cookie "
"WHERE cookie=%s AND name=%s AND ipnr=%s",
(hash, user, req.remote_addr))
else:
cursor.execute("SELECT name FROM auth_cookie "
"WHERE cookie=%s and name=%s",
(hash, user))
row = cursor.fetchone()
if not row:
# The hash is invalid (or has been purged from the database).
# tell the user agent to drop it as it is invalid.
return None
# Now delete it. Use-once token, and the underlying auth module
# will insert new auth info and generate a cookie.
if self.check_ip:
cursor.execute("DELETE FROM auth_cookie "
"WHERE cookie=%s AND name=%s AND ipnr=%s",
(hash, user, req.remote_addr))
else:
cursor.execute("DELETE FROM auth_cookie "
"WHERE cookie=%s and name=%s",
(hash, user))
db.commit()
return user
def _redirect_back(self, req):
"""Redirect the user back to the URL she came from."""
referer = self._referer(req)
if referer and not referer.startswith(req.base_url):
# don't redirect to external sites
referer = None
req.redirect(referer or self.env.abs_href())
def _referer(self, req):
return req.args.get('referer') or req.get_header('Referer')
def enabled(self):
# Users should disable the built-in authentication to use this one
return not self.env.is_component_enabled(auth.LoginModule)
enabled = property(enabled)
# INavigationContributor methods
def get_active_navigation_item(self, req):
return ''
def get_navigation_items(self, req):
if req.authname and req.authname != 'anonymous':
yield ('metanav', 'login', 'logged in as %s' % req.authname)
yield ('metanav', 'logout',
html.A('Logout', href=req.href.logout()))
pass
pass
pass
......@@ -31,13 +31,17 @@ elseif ($wiki == "geni") {
$geniproject->IsMember($this_user, $approved) && $approved)) {
USERERROR("You do not have permission to access the Trac wiki!", 1);
}
$wiki = "protogeni";
$wiki = "protogeni";
$TRACURL = "https://www.protogeni.net/trac/$wiki";
$TRACCOOKIENAME = "trac_auth_protogeni_priv";
}
elseif ($wiki != "emulab") {
USERERROR("Unknown Trac wiki $wiki!", 1);
}
$TRACURL = "https://${USERNODE}/trac/$wiki";
$TRACCOOKIENAME = "trac_auth_${wiki}";
else {
$TRACURL = "https://${USERNODE}/trac/$wiki";
$TRACCOOKIENAME = "trac_auth_${wiki}";
}
#
# Look for our cookie. If the browser has it, then there is nothing
......@@ -57,13 +61,12 @@ SUEXEC($uid, "nobody", "tracxlogin -w " . escapeshellarg($wiki) .
if (!preg_match("/^(\w*)$/", $suexec_output, $matches)) {
TBERROR($suexec_output, 1);
}
setcookie($TRACCOOKIENAME,
$matches[1], 0, "/", $TBAUTHDOMAIN, $TBSECURECOOKIES);
$hash = $matches[1];
if ($wiki == "protogeni") {
$TRACCOOKIENAME = "trac_auth_${wiki}_priv";
setcookie($TRACCOOKIENAME,
$matches[1], 0, "/", $TBAUTHDOMAIN, $TBSECURECOOKIES);
# We do this for the private wiki. Temporary.
setcookie($TRACCOOKIENAME, $hash, 0, "/", $TBAUTHDOMAIN, $TBSECURECOOKIES);
}
header("Location: ${TRACURL}");
header("Location: ${TRACURL}/xlogin?user=$uid&hash=$hash");
?>
......@@ -992,6 +992,8 @@ function DOLOGIN_MAGIC($uid, $uid_idx, $email = null, $adminon = 0)
$TBAUTHDOMAIN, $TBSECURECOOKIES);
setcookie("trac_auth_protogeni", "", $flushtime, "/",
$TBAUTHDOMAIN, $TBSECURECOOKIES);
setcookie("trac_auth_protogeni_priv", "", $flushtime, "/",
$TBAUTHDOMAIN, $TBSECURECOOKIES);
}
DBQueryFatal("update users set ".
......
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