Apache2-AuthCASpbh
view release on metacpan or search on metacpan
lib/Apache2/AuthCASpbh/Authn.pm view on Meta::CPAN
package Apache2::AuthCASpbh::Authn;
use strict;
use warnings;
use APR::URI qw ();
use Apache2::Access qw();
use Apache2::AuthCASpbh qw(cfg_value open_session);
use Apache2::AuthCASpbh::Log qw ();
use Apache2::Const -compile => qw(OK DECLINED SERVER_ERROR
HTTP_MOVED_TEMPORARILY FORBIDDEN);
use Apache2::Log qw();
use Apache2::Module qw();
use Apache2::RequestRec qw();
use Apache2::RequestUtil qw();
use Apache2::ServerRec qw();
use Apache2::URI qw();
use Apache2::Util qw();
use CGI qw ();
use CGI::Cookie qw ();
use LWP::UserAgent qw ();
use Storable qw();
use XML::Simple qw();
our $VERSION = '0.30';
sub handler {
my ($r) = shift;
my $now = time();
my $_log = new Apache2::AuthCASpbh::Log(__PACKAGE__, $r->log);
my $dir_cfg = Apache2::Module::get_config('Apache2::AuthCASpbh',
$r->server, $r->per_dir_config);
my $debug_level = cfg_value($dir_cfg, 'DebugLevel');
$_log->l($debug_level, 'handler called for ' . $r->unparsed_uri);
if (my $r_prev = ($r->prev || $r->main)) {
if (defined $r_prev->user) {
$_log->l($debug_level, "copying user $r_prev->user from previous request");
$r->user($r_prev->user);
return Apache2::Const::OK;
}
}
if ($r->auth_type ne 'Apache2::AuthCASpbh') {
$_log->l($debug_level, "$r->auth_type not our auth type, declining");
return Apache2::Const::DECLINED;
}
$r->push_handlers(PerlCleanupHandler => \&cleanup);
my $session_db = cfg_value($dir_cfg, 'SessionDBPath') . '/' .
cfg_value($dir_cfg, 'SessionDBName');
$_log->l($debug_level, "using session db $session_db");
my $cookie_name = cfg_value($dir_cfg, 'SessionCookieName');
my %cookies = CGI::Cookie->fetch($r);
if (exists($cookies{$cookie_name})) {
$_log->l($debug_level, "found $cookie_name cookie " . $cookies{$cookie_name}->value());
my $session = open_session($session_db, $cookies{$cookie_name}->value());
if (ref($session)) {
if (defined($session->{expiration}) && $session->{expiration} > $now) {
$_log->l($debug_level, 'valid cookie for ' . $session->{user} .
' expires ' . $session->{expiration});
$r->user($session->{user});
if (exists($session->{cas_attributes}) &&
keys %{$session->{cas_attributes}} > 0) {
$_log->l($debug_level, 'session contains attributes');
$r->pnotes(cas_attributes => Storable::dclone($session->{cas_attributes}));
}
if (exists($session->{cas_pgt})) {
$_log->l($debug_level, 'session contains pgt ' .
$session->{cas_pgt});
$r->pnotes(cas_pgt => $session->{cas_pgt});
}
if (exists($session->{cas_proxy})) {
$_log->l($debug_level, 'session contains proxy chain ' .
join(',', @{$session->{cas_proxy}}));
$r->pnotes(cas_proxy => $session->{cas_proxy});
}
$cookies{$cookie_name}->bake($r);
$r->pnotes(cas_session => $session->{_session_id});
untie(%{$session});
return Apache2::Const::OK;
}
else {
$_log->l($debug_level, 'cookie for ' . ($session->{user} // '<missing>') .
' expired ' . ($session->{expiration} // '<missing>'));
eval { tied(%{$session})->delete; };
if ($@) {
$_log->l('warn', "session delete failed - $@");
}
}
}
elsif ($session !~ /Object does not exist in the data store/) {
$_log->l('error', "session tie failed - $session");
return Apache2::Const::SERVER_ERROR;
}
else {
$_log->l($debug_level, "session not found");
}
}
else {
$_log->l($debug_level, "$cookie_name cookie not found");
}
my $q = CGI->new($r, $r->args);
lib/Apache2/AuthCASpbh/Authn.pm view on Meta::CPAN
else {
$_log->l('error', "session tie failed - $pgt_session");
}
return Apache2::Const::SERVER_ERROR;
}
if (exists($pgt_session->{pgtmap}{$pgt_iou})) {
$pgt = $pgt_session->{pgtmap}{$pgt_iou}{pgt};
$_log->l($debug_level, "found pgt $pgt");
delete($pgt_session->{pgtmap}{$pgt_iou});
$pgt_session->{update_count}++;
untie(%{$pgt_session});
$r->pnotes(cas_pgt => $pgt);
}
else {
$_log->l('error', "pgt for $pgt_iou not found in session");
return Apache2::Const::SERVER_ERROR;
}
}
else {
$_log->l($debug_level, 'no pgtiou found in response');
return Apache2::Const::SERVER_ERROR;
}
}
my $cas_attributes = {};
if (exists($cas_success->{'cas:attributes'})) {
foreach (keys %{$cas_success->{'cas:attributes'}}) {
my $key = $_;
$key =~ s/^cas://;
$cas_attributes->{$key} =
$cas_success->{'cas:attributes'}{$_};
}
$_log->l($debug_level, 'found attributes (' .
join(',', keys(%$cas_attributes)) . ')');
$r->pnotes(cas_attributes => Storable::dclone($cas_attributes));
}
my $session = open_session($session_db, '');
if (!ref($session)) {
$_log->l('error', "session create failed - $session");
return Apache2::Const::SERVER_ERROR;
}
$r->pnotes(cas_session => $session->{_session_id});
$session->{user} = $user;
$session->{expiration} = time() + cfg_value($dir_cfg, 'SessionTTL');
$session->{cas_attributes} = $cas_attributes;
$session->{cas_pgt} = $pgt if $pgt;
$session->{cas_proxy} = $cas_proxy if $cas_proxy;
$_log->l($debug_level, 'created session ' . $session->{_session_id} .
' expiration ' . $session->{expiration});
my $cookie = new CGI::Cookie(-name => $cookie_name,
-value => $session->{_session_id},
-secure => cfg_value($dir_cfg,
'SessionCookieSecure'),
-path => defined(cfg_value($dir_cfg,
'SessionCookiePath')) ?
cfg_value($dir_cfg,
'SessionCookiePath') : undef);
$cookie->bake($r);
untie(%{$session});
if (cfg_value($dir_cfg, 'RemoveServiceTicket')) {
$_log->l($debug_level, "removing ticket parameter from request args");
# if $r->args is passed undef, it whines; but can't pass '' as that
# sets args to empty string instead of undef 8-/
no warnings 'uninitialized';
$r->args($qs_nt ? "$qs_nt" : undef);
}
return Apache2::Const::OK;
}
else {
if (exists($cas_data->{'cas:authenticationFailure'})) {
$cas_data->{'cas:authenticationFailure'}{content} =~ s/^[\s\n]*//;
$cas_data->{'cas:authenticationFailure'}{content} =~ s/[\s\n]*$//;
$_log->l('error', 'ticket validation failed - ' .
$cas_data->{'cas:authenticationFailure'}{content} .
'(' . $cas_data->{'cas:authenticationFailure'}{code} . ')');
}
else {
$_log->l('error', "ticket validation invalid response - " .
$response->content());
}
return Apache2::Const::SERVER_ERROR;
}
}
$r->headers_out->{Location} = cfg_value($dir_cfg, 'ServerURL') .
cfg_value($dir_cfg, 'LoginPath') .
"?service=$service";
$_log->l($debug_level, 'redirecting to ' . $r->headers_out->{Location});
return Apache2::Const::HTTP_MOVED_TEMPORARILY;
}
sub cleanup {
my ($r) = shift;
my $now = time();
my $_log = new Apache2::AuthCASpbh::Log(__PACKAGE__, $r->log);
my $dir_cfg = Apache2::Module::get_config('Apache2::AuthCASpbh',
$r->server, $r->per_dir_config);
my $debug_level = cfg_value($dir_cfg, 'DebugLevel');
if (!$r->is_initial_req) {
$_log->l($debug_level, "not initial request, skipping cleanup");
return Apache2::Const::OK;
}
my $session_db = cfg_value($dir_cfg, 'SessionDBPath') . '/' .
cfg_value($dir_cfg, 'SessionDBName');
$_log->l($debug_level, "cleanup using session db $session_db");
$_log->l($debug_level, 'opening global state session ' .
( run in 1.438 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )