Here's something I've written to imitate the University's apache cookieauth module using mod_perl. This is my first experiment with mod_perl, but it seems to work fairly well. Any comments are welcome.
Benefits:
Drawbacks
Download UMNCookieAuth-0.1.4.tgz
Here's the readme file:
NAME
UMN::CookieAuth - Provides cookie authentication for apache 1.x via the
University of Minnesota's central authentication system.
SYNOPSIS
<Location /cookieauth>
PerlAuthenHandler UMN::CookieAuth
AuthType UMN::CookieAuth
PerlAuthzHandler UMN::CookieAuth # optional if you're doing your own
# authorization
Require valid-user # required lest apache
# skip the authentication
# phase altogether
PerlSetVar <option name> "<option value>"
</Location>
DESCRIPTION
Provides cookie authentication against the University of Minnesota's
cookieauth/x500 system for Apache 1.x using mod_perl. The authenticated
user name will be placed in the Apache request object's "user" variable.
Starting with version 0.1.4 the module will also do authorization if
specified via PerlAuthzHandler and an ACL file is specified.
This is beta software. It seems to work for me, but I wouldn't recommend
deploying it anywhere without testing it yourself. This is my first
attempt at doing something useful with mod_perl, so suggestions and/or
criticism are welcome.
This module is modeled after Chris Bongaarts' cookieauth module at
http://www1.umn.edu/is/cookieauth/. Further documentation on the
cookieauth system can be found there.
Installation
Place the UMN directory somewhere in perl's @INC path so mod_perl can
find it. I use the "use lib" directive in a startup.pl script to add my
modules directory to the path when running mod_perl, alternatively you
could install it in system-wide perl module directory. If you want to
use cookieauth_ctl, you'll need to place it in the parent directory of
the UMN directory, install UMN::CookieAuth system-wide, or modify the
script so it knows how to find the module.
The first time the module is executed it will create a shared memory
cache with permissions 0600. This cache will continue to exist even if
you shut down apache. You can use the cookieauth_ctl script to browse
the contents of the shared memory cache or ipcs and ipcrm to manipulate
the shared memory. Note: to access the shared memory cookieauth_ctl will
need to run as the web server user or root.
Sequence of events
If specified as a PerlAuthenHandler, UMN::CookieAuth will inspect each
incoming request.
First, if the request is plain http, the client is redirected to the
secure port of the current server.
If the request is over https, then we look for the authorization cookie.
If the configuration specifies a local cookie (one set by us as
described in "Local Cookies") then we'll look for that first and if
unable to find it, fall back to the global cookie set by the central
auth server. If no local cookie is specified we'll just look for the
global cookie. If no cookies are found we'll redirect the client to the
central auth login site.
If we find a cookie we'll check in a cache in shared memory for it's
decrypted value. If it's not already in the cache, we'll request it's
decrypted value from the central auth server's X500 service and then
store the decrypted value in the cache for the next request.
If the cookie is invalid or expired, or the ip address does not match
the client, or the authentication level is too low, then the client is
redirected to the central auth login server.
Otherwise if the cookie is good we set the apache user value to the user
name retrieved from the decrypted cookie (which should be the user's UMN
internet ID) and allow the client's request to proceed. If the
configuration specifies to use a local cookie, there may be an
additional redirect here simply to set the cookie with the remote
browser.
If the PerlAuthzHandler is specified, then we'll additionally look for
the user name in an Access Control List file (see UMNCookieAuthACLFile).
If the user is to be denied access we'll return a http forbidden
response, otherwise access is granted and the request proceeds.
CONFIGURATION OPTIONS
Configuration options can be set in httpd.conf or .htaccess with the
PerlSetVar directive. I've separated the options into two sections:
"Things you may want to mess with" and "Things you probably don't want
to mess with".
Things you may want to mess with.
UMNCookieAuthACLFile
Default: "". Absolute path name to ACL file. The ACL file itself
should be a series of line separated records in the form "allow
{user_id}" or "deny {user_id}" (e.g. "allow cayfo001" or "deny
cayfo001"). The special user_id value * matches all users. Upon
finding a matching user_id the directive (allow or deny) is applied
and the rest of the file is ignored. Falling off the end of the file
without a match or failing to read the ACLFile both default to "deny
*". Blank lines are ignored as is anything on a line following the
comment character '#'. The ACLFile option is only applicable if you
have specified UMN::CookieAuth as a PerlAuthzHandler, otherwise it
will be ignored.
UMNCookieAuthAllowAnyIP
Default: "". Space or comma separated list of ip addresses for which
we'll allow unmatched cookie ip addresses. Normally if the ip
address encoded in the cookie does not match the remote client we
reject the authentication and redirect them to the login site. If
the remote client is coming through a load balancing proxy this
could be a problem as their ip address would change.
UMNCookieAuthDropUmnCookie
Default: "never". Valid values are "never", "ifnew", and "always".
See "Local Cookies".
UMNCookieAuthHttpsPort
Default: "443". HTTPS port for this server. If we get a plain http
request we'll redirect to the current server using https on this
port.
UMNCookieAuthLevel
Default: "30". U of M authentication level required to access the
location. Values are 20 (new internet id password), 30 (standard
internet id password), 40 (enterprise password), 50 (pgp)
UMNCookieAuthLocalCookieName
Default: "umnAuthV2Local". Name of the parallel cookie we may use
for this local site. See "Local Cookies" below.
UMNCookieAuthLogging
Default: "1". Logging level, currently 0, 1, or 2 in increasing
verbosity. Events should be reported in Apache's error.log.
UMNCookieAuthMaxAge
Default: "3600". Time in seconds until cookie expires. Retroactively
calculated from the time the UM cookie was created.
UMNCookieAuthMemoryKey
Default: "UMCK". Four letter key for IPC shared memory cache. Once a
cookie is decrypted, we store it in shared memory so all apache
children can access it and save themselves a trip to the x500
server. If you want to keep different servers separate you can use a
different key here. Mostly useful for running a development version.
If the module finds a shared memory cache at the specified key, but
with a different cache version, it will increment the key and try
again.
UMNCookieAuthNewCookieLifetime
Default: "300". Expiration time in seconds of the temporary cookie.
UMNCookieAuthNewCookieName
Default: "umnAuthTemp". Name of the one-shot, temporary cookie we
use to track if this is a brand new login from the login server. See
"Local Cookies" below.
UMNCookieAuthUseLocalCookie
Default: "never". Valid values are "never", "ifnew", and "always".
See "Local Cookies".
Things you probably don't want to mess with.
These settings need to synchronize with the University's central
authorization service so you probably won't want to tweak these unless
that changes. Or if you've set up your own auth server.
UMNCookieAuthCookieName
Default: "umnAuthV2". Name of the authentication cookie doled out by
the umn login server.
UMNCookieAuthLoginSite
Default: "https://www.umn.edu/login?desturl=%s". Site to redirect to
for logins. The %s will be replaced by the url originally requested
by the client.
UMNCookieAuthQueryFormat
Default: "WEBCOOKIE\t%s\n". How to format the query to the
authentication server. The %s will be replaced by the encrypted
cookie value. Currently recognized special characters are \t, \r,
and \n. These should be spelled out as here, a literal \ followed by
t, r, or n.
UMNCookieAuthX500Host
Default: "x500.umn.edu". X500 authentication server host. Used to
decrypt the cookie value.
UMNCookieAuthX500Port
Default: "87". TCP port for x500 server.
LOCAL COOKIES
Local cookies are designed to allow a browser to access our site while
dropping unneeded privileges to the rest of the university. Essentially
we copy all the decrypted information from a valid global cookie into a
cookie that we set ourselves and then--optionally--delete the global
cookie. This leads to several configuration options based on the values
of "UseLocalCookie" and "DropUmnCookie"
If UseLocalCookie is set to "never" (the default) authentication will
proceed as usual. The DropUmnCookie setting should have no effect in
this case.
If UseLocalCookie is set to "ifnew", then the module will look for the
NewCookie, which should have been set during any redirection from here
to the login site. If this NewCookie is found it is deleted and the
LocalCookie is set instead with the same value and properties that are
found in the primary UMN cookie. The local cookie will be used for
authentication from then on. If this is not a new login, then
authentication will revert to the UMN cookie.
If UseLocalCookie is set to "always", then the local cookie will always
be used even if we did not initiate the login process.
If DropUmnCookie is set to "never" (the default) the UMN global cookie
will not be affected. The remote user's browser will still hold a global
cookie for the rest of the university.
If DropUmnCookie is set to "ifnew", the UMN cookie will be deleted if we
detect through the NewCookie that this is a new login initiated by us.
This is probably the setting you want if you're using local cookies. If
the remote user already had a global cookie (e.g. they logged into
webmail before coming to our site), then they will still have global
access after coming to our site.
If DropUmnCookie is set to "always", the UMN cookie will be deleted
regardless of how the authentication was initiated. This may cause some
distress as any users will find themselves logged out of their
pre-existing browser sessions after visiting our site.
EXPORT
None. This module uses the object oriented interface from mod_perl. If
you want to use it without being under mod_perl (eg. to query the shared
memory cache as the cookieauth_ctl script does) you can use
UMN::CookieAuth->new() to give you a handler object, although anything
that depends on mod_perl--such as setting cookies--will fail.
AUTHOR
Steve Cayford <cayfo001 @ umn . edu>
REQUIRES
Apache
ssl
mod_perl
Apache::Constants
Apache::Table
Apache::URI
Apache::Cookie
Apache::Log
CGI::Util
IPC::ShareLite
Storable
Net::SSLeay
SEE ALSO
* cookieauth_ctl - Tool for examining the cookieauth shared memory
cache. Needs work, though. Try 'cookieauth_ctl --help' for usage.
* Chris Bongaarts' apache module in C
http://www1.umn.edu/is/cookieauth which inspired this perl
version.
* mod_perl (http://apache.perl.org)
* perl (http://perl.org)
CHANGES
0.1.4, 2005-03-14, by Steve
Added ACLFile option and PerlAuthzHandler functionality. More
documentation.
0.1.3, 2005-02-01, by Steve
Switched the whole module to an object. Improved logging. Added the
whole local cookie concept, which meant rewriting the high level
structure and probably introduced a bunch of new bugs. The shared
memory cache is only cleaned based on a timer value, rather than
every time through. Added AllowAnyIP option. Switched from
Apache::Util::escape_uri() to CGI::Util::escape() -- not sure why
Apache::Util wasn't working.
0.1.2, 2004-12-30, by Steve
Redirect to local https if http rather than straight to the login
server.
0.1.1, 2004-12-16, by Steve
Pulled shared memory connection into a lexical variable reference in
a function, added memory key config, added HttpsPort option, added
documentation.
0.1.0, 2004-10-28, by Steve
Original working version.
BUGS
Nothing serious that I'm aware of yet, but please contact me if you find
anything.
TODO
* Perhaps a rolling timeout, where the timeout could be short (e.g. 5
or 10 minutes), but each successful access resets the timeout. So
this would timeout idle cookies, but not those making constant
access. Along with this we'd probably need a timeout limit to force
re-validation at some point.
* Do we need a separate CacheTimeout option to force re-validation of
cookies as cookieauth does? I'm not sure what the security benefit
is. This will need to use the LocalCookie value for the UMN cookie
if necessary. And may require changing the clean_interval setting.
* Shared memory locking should be handled better. Need to use shared
locks when possible.
* Should provide a "forbidden" page explaining the problem if
credentials are too low or invalid IP rather than just redirecting
to the login site.
* Should provide a logout method - especially for local cookies. Via
the url? Perhaps just tack a ?UmnCookieAuthLogout on the end of the
url. If we see this, delete the cookie(s) and redirect.
* Should there be an option to use a file as the cookie cache instead
of shared memory?
* Suggestions?