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