Restore CAS activation global rule (#1625)

This commit is contained in:
Christophe Maudoux 2019-02-06 22:16:34 +01:00
parent fc316991eb
commit 007a5432f9
2 changed files with 84 additions and 63 deletions

View File

@ -5,26 +5,38 @@ use Mouse;
use URI;
use Lemonldap::NG::Common::FormEncode;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_CAS_SERVICE_NOT_ALLOWED
PE_CONFIRM
PE_ERROR
PE_LOGOUT_OK
PE_OK
PE_SENDRESPONSE
PE_CAS_SERVICE_NOT_ALLOWED
PE_CONFIRM
PE_ERROR
PE_LOGOUT_OK
PE_OK
PE_SENDRESPONSE
);
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Main::Issuer',
'Lemonldap::NG::Portal::Lib::CAS';
'Lemonldap::NG::Portal::Lib::CAS';
# INITIALIZATION
use constant beforeAuth => 'storeEnvAndCheckGateway';
use constant sessionKind => 'ICAS';
has rule => ( is => 'rw', default => sub { {} } );
sub init {
my ($self) = @_;
my $hd = $self->p->HANDLER;
$self->logger->debug( "CAS Rule -> " . $self->conf->{issuerDBCASRule} );
my $rule
= $hd->buildSub( $hd->substitute( $self->conf->{issuerDBCASRule} ) );
unless ($rule) {
$self->error( "Bad CAS rule " . $hd->tsv->{jail}->error );
return 0;
}
$self->{rule} = $rule;
# Launch parents initialization subroutines, then launch IdP en SP lists
my $res = $self->Lemonldap::NG::Portal::Main::Issuer::init();
@ -50,9 +62,9 @@ sub init {
sub storeEnvAndCheckGateway {
my ( $self, $req ) = @_;
my $service = $self->p->getHiddenFormValue( $req, 'service' )
|| $req->param('service');
|| $req->param('service');
my $gateway = $self->p->getHiddenFormValue( $req, 'gateway' )
|| $req->param('gateway');
|| $req->param('gateway');
if ( $gateway and $gateway eq "true" ) {
$self->logger->debug(
@ -78,6 +90,11 @@ sub storeEnvAndCheckGateway {
sub run {
my ( $self, $req, $target ) = @_;
unless ( $self->rule->( $req, $req->sessionInfo ) ) {
$self->userLogger->error('CAS service not authorized');
return PE_CAS_SERVICE_NOT_ALLOWED;
}
# CAS URL
my $cas_login = 'login';
my $cas_logout = 'logout';
@ -104,18 +121,18 @@ sub run {
# GET parameters
my $service = $self->p->getHiddenFormValue( $req, 'service' )
|| $req->param('service');
my $renew =
$self->p->getHiddenFormValue( $req, 'renew' ) || $req->param('renew');
|| $req->param('service');
my $renew = $self->p->getHiddenFormValue( $req, 'renew' )
|| $req->param('renew');
my $gateway = $self->p->getHiddenFormValue( $req, 'gateway' )
|| $req->param('gateway');
|| $req->param('gateway');
my $casServiceTicket;
# Renew
if ( $renew
and $renew eq 'true'
and time - $req->sessionInfo->{_utime} >
$self->conf->{portalForceAuthnInterval} )
and time - $req->sessionInfo->{_utime}
> $self->conf->{portalForceAuthnInterval} )
{
# Authentication must be replayed
@ -151,7 +168,8 @@ sub run {
}
if ( my $rule = $self->spRules->{$app} ) {
if ( $rule->( $req, $req->sessionInfo ) ) {
$self->logger->debug("CAS service $service access allowed");
$self->logger->debug(
"CAS service $service access allowed");
}
else {
@ -160,14 +178,15 @@ sub run {
if ( $casAccessControlPolicy =~ /^(error)$/i ) {
$self->logger->debug(
"Return error instead of redirecting user on CAS service"
"Return error instead of redirecting user on CAS service"
);
return PE_CAS_SERVICE_NOT_ALLOWED;
}
else {
$self->logger->debug(
"Redirect user on CAS service with a fake ticket");
"Redirect user on CAS service with a fake ticket"
);
$casServiceTicket = "ST-F4K3T1CK3T";
}
}
@ -179,10 +198,10 @@ sub run {
# Check last authentication time to decide if
# the authentication is recent or not
my $casRenewFlag = 0;
my $last_authn_utime = $req->{sessionInfo}->{_lastAuthnUTime} || 0;
if (
time() - $last_authn_utime <
$self->conf->{portalForceAuthnInterval} )
my $last_authn_utime
= $req->{sessionInfo}->{_lastAuthnUTime} || 0;
if (time() - $last_authn_utime
< $self->conf->{portalForceAuthnInterval} )
{
$self->logger->debug(
"Authentication is recent, will set CAS renew flag to true"
@ -219,7 +238,7 @@ sub run {
# Redirect to service
my $service_url = $service;
$service_url .= ( $service =~ /\?/ ? '&' : '?' )
. build_urlencoded( ticket => $casServiceTicket );
. build_urlencoded( ticket => $casServiceTicket );
$self->logger->debug("Redirect user to $service_url");
@ -296,7 +315,8 @@ sub run {
}
# 4. SERVICE VALIDATE [CAS 2.0]
if ( $target eq $cas_serviceValidate || $target eq $cas_p3_serviceValidate )
if ( $target eq $cas_serviceValidate
|| $target eq $cas_p3_serviceValidate )
{
$self->logger->debug(
@ -304,7 +324,8 @@ sub run {
# This URL must not be called by authenticated users
$self->userLogger->info(
"CAS SERVICE VALIDATE URL called by authenticated user, ignore it");
"CAS SERVICE VALIDATE URL called by authenticated user, ignore it"
);
return PE_OK;
}
@ -312,7 +333,8 @@ sub run {
# 5. PROXY VALIDATE [CAS 2.0]
if ( $target eq $cas_proxyValidate || $target eq $cas_p3_proxyValidate ) {
$self->logger->debug("URL $url detected as an CAS PROXY VALIDATE URL");
$self->logger->debug(
"URL $url detected as an CAS PROXY VALIDATE URL");
# This URL must not be called by authenticated users
$self->userLogger->info(
@ -394,20 +416,21 @@ sub validate {
or $service2_uri->rel($service1_uri) eq "./" )
{
$self->logger->notice(
"Submitted service $service1_uri does not exactly match initial service "
. $service2_uri
. ' but difference is tolerated.' );
"Submitted service $service1_uri does not exactly match initial service "
. $service2_uri
. ' but difference is tolerated.' );
}
else {
$self->logger->error(
"Submitted service $service does not match initial service "
. $casServiceSession->data->{service} );
. $casServiceSession->data->{service} );
$self->deleteCasSession($casServiceSession);
return $self->returnCasValidateError();
}
}
else {
$self->logger->debug("Submitted service $service math initial servce");
$self->logger->debug(
"Submitted service $service math initial servce");
}
# Check renew
@ -418,7 +441,7 @@ sub validate {
unless ( $casServiceSession->data->{renew} ) {
$self->logger->error(
"Authentication renew requested, but not done in former authentication process"
"Authentication renew requested, but not done in former authentication process"
);
$self->deleteCasSession($casServiceSession);
return $self->returnCasValidateError();
@ -426,21 +449,20 @@ sub validate {
}
# Open local session
my $localSession =
$self->p->getApacheSession( $casServiceSession->data->{_cas_id} );
my $localSession
= $self->p->getApacheSession( $casServiceSession->data->{_cas_id} );
unless ($localSession) {
$self->logger->warn( "Local session "
. $casServiceSession->data->{_cas_id}
. " notfound" );
. $casServiceSession->data->{_cas_id}
. " notfound" );
$self->deleteCasSession($casServiceSession);
return $self->returnCasValidateError();
}
# Get username
my $username =
$localSession->data->{ $self->conf->{casAttr}
|| $self->conf->{whatToTrace} };
my $username = $localSession->data->{ $self->conf->{casAttr}
|| $self->conf->{whatToTrace} };
$self->logger->debug("Get username $username");
@ -549,8 +571,8 @@ sub _validate2 {
}
$self->logger->debug( "Get "
. lc($urlType)
. " validate request with ticket $ticket for service $service" );
. lc($urlType)
. " validate request with ticket $ticket for service $service" );
# Get CAS session corresponding to ticket
if ( $urlType eq 'SERVICE' and !( $ticket =~ s/^ST-// ) ) {
@ -587,14 +609,14 @@ sub _validate2 {
or $service2_uri->rel($service1_uri) eq "./" )
{
$self->logger->notice(
"Submitted service $service1_uri does not exactly match initial service "
. $service2_uri
. ' but difference is tolerated.' );
"Submitted service $service1_uri does not exactly match initial service "
. $service2_uri
. ' but difference is tolerated.' );
}
else {
$self->userLogger->error(
"Submitted service $service does not match initial service "
. $casServiceSession->data->{service} );
. $casServiceSession->data->{service} );
$self->deleteCasSession($casServiceSession);
return $self->returnCasServiceValidateError( $req,
'INVALID_SERVICE',
@ -614,7 +636,7 @@ sub _validate2 {
unless ( $casServiceSession->data->{renew} ) {
$self->logger->error(
"Authentication renew requested, but not done in former authentication process"
"Authentication renew requested, but not done in former authentication process"
);
$self->deleteCasSession($casServiceSession);
return $self->returnCasValidateError();
@ -653,7 +675,7 @@ sub _validate2 {
if ($casProxyGrantingSession) {
my $casProxyGrantingSessionID = $casProxyGrantingSession->id;
my $casProxyGrantingTicket = "PGT-" . $casProxyGrantingSessionID;
my $casProxyGrantingTicket = "PGT-" . $casProxyGrantingSessionID;
$self->logger->debug(
"CAS proxy granting session $casProxyGrantingSessionID created"
@ -667,16 +689,15 @@ sub _validate2 {
$casProxyGrantingTicketIOU = "PGTIOU-" . $tmpCasSession->id;
$self->deleteCasSession($tmpCasSession);
$self->logger->debug(
"Generate proxy granting ticket IOU $casProxyGrantingTicketIOU"
"Generate proxy granting ticket IOU $casProxyGrantingTicketIOU"
);
# Request pgtUrl
if (
$self->callPgtUrl(
if ($self->callPgtUrl(
$pgtUrl, $casProxyGrantingTicketIOU,
$casProxyGrantingTicket
)
)
)
{
$self->logger->debug(
"Proxy granting URL $pgtUrl called with success");
@ -696,31 +717,30 @@ sub _validate2 {
}
# Open local session
my $localSession =
$self->p->getApacheSession( $casServiceSession->data->{_cas_id} );
my $localSession
= $self->p->getApacheSession( $casServiceSession->data->{_cas_id} );
unless ($localSession) {
$self->userLogger->error( "Local session "
. $casServiceSession->data->{_cas_id}
. " notfound" );
. $casServiceSession->data->{_cas_id}
. " notfound" );
$self->deleteCasSession($casServiceSession);
return $self->returnCasServiceValidateError( $req, 'INTERNAL_ERROR',
'No session associated to ticket' );
}
# Get username
my $username =
$localSession->data->{ $self->conf->{casAttr}
|| $self->conf->{whatToTrace} };
my $username = $localSession->data->{ $self->conf->{casAttr}
|| $self->conf->{whatToTrace} };
$self->logger->debug("Get username $username");
# Get attributes [CAS 3.0]
my $attributes = {};
my $ev =
( $app and $self->conf->{casAppMetaDataExportedVars}->{$app} )
? $self->conf->{casAppMetaDataExportedVars}->{$app}
: {};
my $ev
= ( $app and $self->conf->{casAppMetaDataExportedVars}->{$app} )
? $self->conf->{casAppMetaDataExportedVars}->{$app}
: {};
unless (%$ev) {
$ev = $self->conf->{casAttributes} || {};
}
@ -728,7 +748,7 @@ sub _validate2 {
foreach my $casAttribute ( keys %$ev ) {
my $localSessionValue = $localSession->data->{ $ev->{$casAttribute} };
$attributes->{$casAttribute} = $localSessionValue
if defined $localSessionValue;
if defined $localSessionValue;
}
# Return success message

View File

@ -217,6 +217,7 @@ sub issuer {
authentication => 'Demo',
userDB => 'Same',
issuerDBCASActivation => 1,
issuerDBCASRule => '$uid eq "french"',
casAttr => 'uid',
casAccessControlPolicy => 'error',
multiValuesSeparator => ';',