view release on metacpan or search on metacpan
lib/Apache2/AuthCAS.pm view on Meta::CPAN
"DbDriver" => "Pg",
"DbDataSource" => "dbname=apache_cas;host=localhost;port=5432",
"DbSessionTable" => "cas_sessions",
"DbUser" => "cas",
"DbPass" => "cas",
);
# default to 0
$SESSION_CLEANUP_COUNTER = 0 if (!defined($SESSION_CLEANUP_COUNTER));
sub dbConnect($)
{
my($self) = @_;
my $dbh = DBI->connect(
"dbi:" . $self->casConfig("DbDriver")
. ":" . $self->casConfig("DbDataSource"),
$self->casConfig("DbUser"), $self->casConfig("DbPass"),
{ AutoCommit => 1 }
);
if (!defined($dbh))
{
$self->logMsg("db connect error: $DBI::errstr");
return undef;
}
return $dbh;
}
sub getApacheConfig($)
{
my($self) = @_;
$self->{'casConfig'} = Apache2::Module::get_config('Apache2::AuthCAS::Configuration'
, $self->{'request'}->server
, $self->{'request'}->per_dir_config);
# Now add in our defaults
foreach my $key (keys(%DEFAULTS))
{
$self->{'casConfig'}->{$key} = $DEFAULTS{$key}
lib/Apache2/AuthCAS.pm view on Meta::CPAN
}
$self->logMsg("Apache Config:", $LOG_DEBUG);
foreach my $key (sort(keys(%{$self->{'casConfig'}})))
{
my $val = $self->casConfig($key) || 'undef';
$self->logMsg(" $key => $val", $LOG_DEBUG);
}
}
sub casConfig($$)
{
my($self, $var) = @_;
return $self->{'casConfig'}->{$var};
}
sub logMsg($$;$)
{
my($self, $msg, $logLevel) = @_;
$logLevel = $LOG_ERROR if (!$logLevel);
if ($self->casConfig("LogLevel") >= $logLevel)
{
my $sub = (caller(1))[3];
$sub =~ /(\w+)$/;
$self->{'request'}->log->alert("CAS($$): $1: $msg");
}
}
# used for underlying services that need proxy tickets (PTs)
sub authenticate($$)
{
my($class, $r) = @_;
# Only authenticate the first internal request
return (Apache2::Const::OK) unless $r->is_initial_req;
# Let's make this easy on ourselves and pass an object around
# for reading config variables and the request object
my $self = {};
bless($self, ref $class || $class);
lib/Apache2/AuthCAS.pm view on Meta::CPAN
return $self->redirect_without_ticket() if ($self->casConfig("RemoveTicket"));
return (Apache2::Const::OK);
}
}
# No valid session, no ticket. Redirect to CAS login
return $self->redirect_login();
}
sub check_session($$$)
{
my($self, $sid) = @_;
# we set up our own session here, so that we don't have to continually
# go through this whole process! we associate a session id with a PGTIOU
# try to get a session record for the session id we received
# session_data - session id, last accessed, netid, pgtiou
if (my($last_accessed, $user, $pgt) = $self->get_session_data($sid))
{
lib/Apache2/AuthCAS.pm view on Meta::CPAN
}
}
else
{
$self->logMsg("session '$sid' is invalid", $LOG_DEBUG);
}
return undef;
}
sub cleanup()
{
my($self) = @_;
$SESSION_CLEANUP_COUNTER++;
$self->logMsg("counter=$SESSION_CLEANUP_COUNTER", $LOG_DEBUG);
# perform session cleanup
if ($SESSION_CLEANUP_COUNTER == 1)
{
$self->delete_expired_sessions();
}
# reset counter if we have reached our threshold
$SESSION_CLEANUP_COUNTER = 0
if ($SESSION_CLEANUP_COUNTER >= $self->casConfig("SessionCleanupThreshold"));
}
sub add_basic_auth($$)
{
my($self, $user) = @_;
if ($self->casConfig("PretendBasicAuth"))
{
# setup this up for underlying authz modules that rely
# on Basic auth having been performed
$self->setHeader(1, 'Authorization'
, "Basic " . encode_base64($user . ":DUMMYPASS"));
$self->{'request'}->ap_auth_type("Basic");
$self->{'request'}->user($user);
}
}
sub redirect_without_ticket($)
{
my($self) = @_;
$self->logMsg("redirecting to remove service ticket from service string", $LOG_INFO);
$self->setHeader(0, 'Location', $self->this_url());
return (Apache2::Const::HTTP_MOVED_TEMPORARILY);
}
sub redirect_login($)
{
my($self) = @_;
$self->logMsg("start", $LOG_DEBUG);
my $service = $self->this_url(1);
$self->logMsg("redirecting to CAS for service: '$service'", $LOG_INFO);
$service = uri_escape($service);
$self->setHeader(0, 'Location', "https://"
. $self->casConfig("Host") . ":" . $self->casConfig("Port")
. $self->casConfig("LoginUri") . "?service=$service");
return (Apache2::Const::HTTP_MOVED_TEMPORARILY);
}
sub redirect($;$$)
{
my($self, $url, $errcode) = @_;
if ($url)
{
my $service = $self->this_url(1);
$self->logMsg("redirecting to url: '$url' service: '$service'", $LOG_INFO);
$self->setHeader(0, 'CAS_FILTER_CAS_HOST', $self->casConfig("Host"));
$self->setHeader(0, 'CAS_FILTER_CAS_PORT', $self->casConfig("Port"));
lib/Apache2/AuthCAS.pm view on Meta::CPAN
return (Apache2::Const::HTTP_OK);
}
}
# params
# apache request object
# ticket to be validated
# returns a hash with keys on success
# 'user', 'pgtiou'
# NULL on failure
sub validate_service_ticket($$$)
{
my($self, $ticket) = @_;
my $proxy = $self->casConfig("ProxyService") ? "1" : "0";
my $service = $self->this_url(1);
$self->logMsg("Validating service ticket '$ticket' for service '$service'", $LOG_DEBUG);
my $url;
if ($proxy)
lib/Apache2/AuthCAS.pm view on Meta::CPAN
}
else
{
$self->logMsg("invalid service response", $LOG_DEBUG);
$errorMsg = $ERROR_CODES{"INVALID_RESPONSE"};
}
return ($errorMsg, $user, $pgtiou);
}
sub proxy_receptor($$$)
{
my($self, $pgtiou, $pgt) = @_;
# This is the proxy receptor.
# We should only enter here when CAS sends us the PGTIOU and the PGT
if ($pgtiou and $pgt)
{
$self->logMsg("proxy receptor invoked with '$pgtiou' => '$pgt'", $LOG_DEBUG);
# save the pgtiou/pgt mapping
lib/Apache2/AuthCAS.pm view on Meta::CPAN
return (Apache2::Const::OK);
}
else
{
$self->logMsg("invalid proxy receptor call - missing ticket information"
, $LOG_DEBUG);
return $self->redirect($self->casConfig("ErrorUrl") , $ERROR_CODES{"PGT_RECEPTOR"});
}
}
sub send_proxysuccess($$)
{
my($self) = @_;
$self->logMsg("sending proxy success for CAS callback", $LOG_DEBUG);
$self->{'request'}->content_type("text/html");
$self->{'request'}->print("<casClient:proxySuccess xmlns:casClient=\"http://www.yale.edu/tp/casClient\"/>\n");
$self->{'request'}->rflush();
return (Apache2::Const::OK);
}
sub get_proxy_tickets($$;$$)
{
my($self, $pgt, $target, $numTickets) = @_;
return () if (!$target or !$numTickets);
$self->logMsg("retrieving '$numTickets' PTs for PGT='$pgt', target='$target'", $LOG_DEBUG);
my @tickets = ();
# Net::SSLeay::trace options
lib/Apache2/AuthCAS.pm view on Meta::CPAN
{
$self->logMsg("invalid proxy ticket response", $LOG_DEBUG);
return ();
}
}
return @tickets;
}
# place data in the session
sub create_session($$$$)
{
my($self, $uid, $pgtiou, $ticket) = @_;
$self->logMsg("creating session for uid='$uid'"
. ($pgtiou ? ", pgtiou='$pgtiou'" : ""), $LOG_DEBUG);
my $sid = sprintf("%10d-", time());
srand();
for (my $i = 0; $i < 21; $i++)
{
lib/Apache2/AuthCAS.pm view on Meta::CPAN
$self->logMsg("error creating session ($DBI::errstr)", $LOG_DEBUG);
undef($sid);
}
$dbh->disconnect();
return $sid;
}
# "touch" the session
sub touch_session($$)
{
my($self, $sid) = @_;
$self->logMsg("touching session '$sid'", $LOG_DEBUG);
my $dbh = $self->dbConnect() or return 0;
$dbh->do("UPDATE " . $self->casConfig("DbSessionTable")
. " SET last_accessed = ? WHERE id = ?"
, undef, time(), $sid
lib/Apache2/AuthCAS.pm view on Meta::CPAN
$self->logMsg("error touching session ($DBI::errstr)", $LOG_DEBUG);
$rc = 0;
}
$dbh->disconnect();
return $rc;
}
# takes a session id and returns an array
sub get_session_data($$)
{
my($self, $sid) = @_;
$self->logMsg("retrieving session data for sid='$sid'", $LOG_DEBUG);
# retrieve a session object for this session id
my $dbh = $self->dbConnect() or return ();
my($last_accessed, $uid, $pgt) = $dbh->selectrow_array(
"SELECT last_accessed, user_id, pgt FROM "
lib/Apache2/AuthCAS.pm view on Meta::CPAN
. " last_accessed='$last_accessed' uid='$uid'"
. ($pgt ? "pgt='$pgt'" : ""), $LOG_DEBUG);
return ($last_accessed, $uid, $pgt);
}
$self->logMsg("couldn't get session data for sid='$sid'", $LOG_DEBUG);
return ();
}
# delete session
sub delete_session_data($$)
{
my($self, $sid) = @_;
$self->logMsg("deleting session mapping for sid='$sid'", $LOG_DEBUG);
# retrieve a session object for this session id
my $dbh = $self->dbConnect() or return 0;
$dbh->do("DELETE FROM " . $self->casConfig("DbSessionTable") . " WHERE id = ?"
, undef, $sid
lib/Apache2/AuthCAS.pm view on Meta::CPAN
$self->logMsg("error deleting session mapping for sid='$sid' ($DBI::errstr)", $LOG_DEBUG);
$rc = 0;
}
$dbh->disconnect();
return $rc;
}
# delete expired sessions
sub delete_expired_sessions($)
{
my($self) = @_;
my $oldestValidTime = time() - $self->casConfig("SessionTimeout");
$self->logMsg("deleting sessions older than '$oldestValidTime'", $LOG_DEBUG);
# retrieve a session object for this session id
my $dbh = $self->dbConnect() or return 0;
$dbh->do("DELETE FROM " . $self->casConfig("DbSessionTable")
lib/Apache2/AuthCAS.pm view on Meta::CPAN
$self->logMsg("error deleting expired sessions ($DBI::errstr)", $LOG_ERROR);
$rc = 0;
}
$dbh->disconnect();
return $rc;
}
# place the pgt mapping in the database
sub set_pgt($$$)
{
my($self, $pgtiou, $pgt) = @_;
$self->logMsg("adding map for pgtiou='$pgtiou' pgt='$pgt'", $LOG_DEBUG);
my $dbh = $self->dbConnect() or return 0;
$dbh->do(
"UPDATE " . $self->casConfig("DbSessionTable") . "
SET pgt = ?
lib/Apache2/AuthCAS.pm view on Meta::CPAN
{
$self->logMsg("error adding map ($DBI::errstr)", $LOG_ERROR);
$rc = 0;
}
$dbh->disconnect();
return $rc;
}
sub do_proxy($$$$$$)
{
my($self, $sid, $pgt, $user, $removeTicket) = @_;
$self->logMsg("proxying request, sid='$sid'", $LOG_DEBUG);
$self->logMsg("pgt='$pgt'", $LOG_DEBUG) if ($pgt);
if (!$pgt)
{
my(@sessionData) = $self->get_session_data($sid);
$pgt = $sessionData[2];
lib/Apache2/AuthCAS.pm view on Meta::CPAN
return (Apache2::Const::OK);
}
else
{
$self->delete_session_data($sid);
return $self->redirect($self->casConfig("ErrorUrl")
, $ERROR_CODES{"INVALID_PGT"});
}
}
sub setHeader($$$$)
{
my($self, $in, $header, $value) = @_;
$self->logMsg("Setting header: $header = $value", $LOG_DEBUG);
if ($in)
{
$self->{'request'}->headers_in->{$header} = $value;
}
else
{
$self->{'request'}->headers_out->{$header} = $value;
}
}
# strips the ticket from the query and returns the full service URL
sub this_url($$;$)
{
my($self, $serviceOverride) = @_;
if ($serviceOverride and my $service = $self->casConfig("Service"))
{
return $service;
}
my $url = $self->{'request'}->construct_url();
my $uri = $self->{'request'}->parsed_uri;
lib/Apache2/AuthCAS.pm view on Meta::CPAN
$url .= "?$query" if ($query ne "");
}
elsif ($self->{'request'}->unparsed_uri =~ /\?$/)
{
$url .= "?";
}
return $url;
}
sub parse_query_parameters($$)
{
my($self, $query) = @_;
return () if (!$query);
my %params = ();
foreach my $param (split(/&/, $query))
{
my($key, $value) = split(/=/, $param);
lib/Apache2/AuthCAS/Configuration.pm view on Meta::CPAN
Apache2::ServerUtil->server->log->debug("merge: $key => $b");
Apache2::ServerUtil->server->log->debug(" $key => $a");
}
$merged{$key} = $base->{$key} if exists($base->{$key});
$merged{$key} = $add->{$key} if exists($add->{$key});
}
return bless(\%merged, ref($base));
}
sub CASConfig($$$)
{
my ($self, $parms, $data) = @_;
my $which = $parms->info();
Apache2::ServerUtil->server->log->debug(" Setting $which to $data");
if ($which eq "LogLevel")
{
# Validate the argument is a valid log level
unless ($data >= 0 and $data <= 4)