2010-08-23 17:47:53 +02:00
|
|
|
## @file
|
|
|
|
# CAS Issuer file
|
|
|
|
|
|
|
|
## @class
|
|
|
|
# CAS Issuer class
|
|
|
|
package Lemonldap::NG::Portal::IssuerDBCAS;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use Lemonldap::NG::Portal::Simple;
|
2010-08-25 16:23:45 +02:00
|
|
|
use Lemonldap::NG::Portal::_CAS;
|
2011-09-15 11:42:25 +02:00
|
|
|
use base qw(Lemonldap::NG::Portal::_CAS Lemonldap::NG::Portal::_LibAccess);
|
2010-08-23 17:47:53 +02:00
|
|
|
|
2011-12-05 16:58:20 +01:00
|
|
|
our $VERSION = '1.2.0';
|
2010-08-23 17:47:53 +02:00
|
|
|
|
|
|
|
## @method void issuerDBInit()
|
2010-08-23 18:41:38 +02:00
|
|
|
# Nothing to do
|
2010-08-23 17:47:53 +02:00
|
|
|
# @return Lemonldap::NG::Portal error code
|
|
|
|
sub issuerDBInit {
|
|
|
|
my $self = shift;
|
2010-08-26 10:42:28 +02:00
|
|
|
|
|
|
|
return PE_OK;
|
2010-08-23 17:47:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
## @apmethod int issuerForUnAuthUser()
|
2010-08-23 18:41:38 +02:00
|
|
|
# Manage CAS request for unauthenticated user
|
2010-08-23 17:47:53 +02:00
|
|
|
# @return Lemonldap::NG::Portal error code
|
|
|
|
sub issuerForUnAuthUser {
|
|
|
|
my $self = shift;
|
2010-08-23 18:41:38 +02:00
|
|
|
|
|
|
|
# CAS URLs
|
2011-12-05 16:58:20 +01:00
|
|
|
my $cas_login_url = '/cas/login';
|
|
|
|
my $cas_logout_url = '/cas/logout';
|
|
|
|
my $cas_validate_url = '/cas/validate';
|
|
|
|
my $cas_serviceValidate_url = '/cas/serviceValidate';
|
|
|
|
my $cas_proxyValidate_url = '/cas/proxyValidate';
|
|
|
|
my $cas_proxy_url = '/cas/proxy';
|
2010-08-25 16:23:45 +02:00
|
|
|
|
|
|
|
# Called URL
|
2011-12-05 16:58:20 +01:00
|
|
|
my $url = $self->url( -absolute => 1 );
|
2010-08-25 16:23:45 +02:00
|
|
|
|
|
|
|
# 1. LOGIN
|
|
|
|
if ( $url =~ /\Q$cas_login_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS LOGIN URL", 'debug' );
|
|
|
|
|
|
|
|
# GET parameters
|
|
|
|
my $service = $self->getHiddenFormValue('service')
|
|
|
|
|| $self->param('service');
|
|
|
|
my $renew = $self->getHiddenFormValue('renew') || $self->param('renew');
|
|
|
|
my $gateway = $self->getHiddenFormValue('gateway')
|
|
|
|
|| $self->param('gateway');
|
|
|
|
|
|
|
|
# Keep values in hidden fields
|
|
|
|
$self->setHiddenFormValue( 'service', $service );
|
|
|
|
$self->setHiddenFormValue( 'renew', $renew );
|
|
|
|
$self->setHiddenFormValue( 'gateway', $gateway );
|
|
|
|
|
|
|
|
# Gateway
|
|
|
|
if ( $gateway eq 'true' ) {
|
2010-08-25 17:33:33 +02:00
|
|
|
|
2010-08-27 18:07:19 +02:00
|
|
|
# User should already be authenticated
|
|
|
|
$self->lmLog(
|
|
|
|
"Gateway authentication requested, but user is not logged in",
|
|
|
|
'error' );
|
|
|
|
|
|
|
|
# Redirect user to the service
|
|
|
|
$self->lmLog( "Redirect user to $service", 'debug' );
|
|
|
|
|
|
|
|
$self->{urldc} = $service;
|
|
|
|
|
|
|
|
return $self->_subProcess(qw(autoRedirect));
|
2010-08-25 17:33:33 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# 2. LOGOUT
|
|
|
|
if ( $url =~ /\Q$cas_logout_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS LOGOUT URL", 'debug' );
|
|
|
|
|
|
|
|
# GET parameters
|
|
|
|
my $logout_url = $self->param('url');
|
|
|
|
|
|
|
|
if ($logout_url) {
|
|
|
|
|
2010-08-27 18:07:19 +02:00
|
|
|
# Display a link to the provided URL
|
|
|
|
$self->lmLog( "Logout URL $logout_url will be displayed", 'debug' );
|
|
|
|
|
|
|
|
$self->info(
|
|
|
|
"<h3>"
|
|
|
|
. &Lemonldap::NG::Portal::_i18n::msg( PM_BACKTOCASURL,
|
|
|
|
$ENV{HTTP_ACCEPT_LANGUAGE} )
|
|
|
|
. "</h3>"
|
|
|
|
);
|
|
|
|
$self->info("<p><a href=\"$logout_url\">$logout_url</a></p>");
|
|
|
|
$self->{activeTimer} = 0;
|
|
|
|
|
|
|
|
return PE_CONFIRM;
|
2010-08-25 17:33:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return PE_LOGOUT_OK;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# 3. VALIDATE [CAS 1.0]
|
|
|
|
if ( $url =~ /\Q$cas_validate_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS VALIDATE URL", 'debug' );
|
|
|
|
|
|
|
|
# GET parameters
|
|
|
|
my $service = $self->param('service');
|
|
|
|
my $ticket = $self->param('ticket');
|
|
|
|
my $renew = $self->param('renew');
|
|
|
|
|
|
|
|
# Required parameters: service and ticket
|
|
|
|
unless ( $service and $ticket ) {
|
|
|
|
$self->lmLog( "Service and Ticket parameters required", 'error' );
|
|
|
|
$self->returnCasValidateError();
|
|
|
|
}
|
|
|
|
|
2010-08-25 17:57:21 +02:00
|
|
|
$self->lmLog(
|
|
|
|
"Get validate request with ticket $ticket for service $service",
|
|
|
|
'debug' );
|
|
|
|
|
2010-08-25 17:33:33 +02:00
|
|
|
my $casServiceSession = $self->getCasSession($ticket);
|
|
|
|
|
|
|
|
unless ($casServiceSession) {
|
|
|
|
$self->lmLog( "Service ticket session $ticket not found", 'error' );
|
|
|
|
$self->returnCasValidateError();
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Service ticket session $ticket found", 'debug' );
|
|
|
|
|
|
|
|
# Check service
|
|
|
|
unless ( $service eq $casServiceSession->{service} ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Submitted service $service does not match initial service "
|
|
|
|
. $casServiceSession->{service},
|
|
|
|
'error'
|
|
|
|
);
|
|
|
|
untie %$casServiceSession;
|
|
|
|
$self->returnCasValidateError();
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Submitted service $service math initial servce",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# Check renew
|
|
|
|
if ( $renew eq 'true' ) {
|
|
|
|
|
|
|
|
# We should check the ST was delivered with primary credentials
|
2010-08-30 11:24:04 +02:00
|
|
|
$self->lmLog( "Renew flag detected ", 'debug' );
|
|
|
|
|
|
|
|
unless ( $casServiceSession->{renew} ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Authentication renew requested, but not done in former authentication process",
|
|
|
|
'error'
|
|
|
|
);
|
|
|
|
untie %$casServiceSession;
|
|
|
|
$self->returnCasValidateError();
|
|
|
|
}
|
2010-08-25 17:33:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Open local session
|
|
|
|
my $localSession =
|
2010-08-26 10:42:28 +02:00
|
|
|
$self->getApacheSession( $casServiceSession->{_cas_id}, 1 );
|
2010-08-25 17:33:33 +02:00
|
|
|
|
|
|
|
unless ($localSession) {
|
|
|
|
$self->lmLog(
|
2010-08-26 10:42:28 +02:00
|
|
|
"Local session " . $casServiceSession->{_cas_id} . " notfound",
|
|
|
|
'error'
|
|
|
|
);
|
2010-08-25 17:33:33 +02:00
|
|
|
untie %$casServiceSession;
|
|
|
|
$self->returnCasValidateError();
|
2010-08-25 16:23:45 +02:00
|
|
|
}
|
|
|
|
|
2010-08-25 17:33:33 +02:00
|
|
|
# Get username
|
2010-10-14 11:50:23 +02:00
|
|
|
my $username =
|
|
|
|
$localSession->{ $self->{casAttr} || $self->{whatToTrace} };
|
2010-08-25 17:33:33 +02:00
|
|
|
|
|
|
|
$self->lmLog( "Get username $username", 'debug' );
|
|
|
|
|
|
|
|
# Close sessions
|
|
|
|
untie %$casServiceSession;
|
|
|
|
untie %$localSession;
|
|
|
|
|
|
|
|
# Return success message
|
|
|
|
$self->returnCasValidateSuccess($username);
|
|
|
|
|
|
|
|
# We should not be there
|
|
|
|
return PE_ERROR;
|
2010-08-25 16:23:45 +02:00
|
|
|
}
|
2010-08-23 18:41:38 +02:00
|
|
|
|
2010-08-26 14:24:38 +02:00
|
|
|
# 4. SERVICE VALIDATE [CAS 2.0]
|
2010-08-26 18:16:13 +02:00
|
|
|
# 5. PROXY VALIDATE [CAS 2.0]
|
|
|
|
if ( $url =~ /(\Q$cas_serviceValidate_url\E|\Q$cas_proxyValidate_url\E)/io )
|
|
|
|
{
|
2010-08-26 14:24:38 +02:00
|
|
|
|
2010-08-26 18:16:13 +02:00
|
|
|
my $urlType =
|
|
|
|
( $url =~ /\Q$cas_serviceValidate_url\E/ ? 'SERVICE' : 'PROXY' );
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS $urlType VALIDATE URL",
|
2010-08-26 14:24:38 +02:00
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# GET parameters
|
|
|
|
my $service = $self->param('service');
|
|
|
|
my $ticket = $self->param('ticket');
|
|
|
|
my $pgtUrl = $self->param('pgtUrl');
|
|
|
|
my $renew = $self->param('renew');
|
|
|
|
|
2010-08-26 16:43:32 +02:00
|
|
|
# PGTIOU
|
|
|
|
my $casProxyGrantingTicketIOU;
|
|
|
|
|
2010-08-26 14:24:38 +02:00
|
|
|
# Required parameters: service and ticket
|
|
|
|
unless ( $service and $ticket ) {
|
|
|
|
$self->lmLog( "Service and Ticket parameters required", 'error' );
|
|
|
|
$self->returnCasServiceValidateError( 'INVALID_REQUEST',
|
|
|
|
'Missing mandatory parameters (service, ticket)' );
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog(
|
2010-08-26 18:16:13 +02:00
|
|
|
"Get "
|
|
|
|
. lc($urlType)
|
|
|
|
. " validate request with ticket $ticket for service $service",
|
2010-08-26 14:24:38 +02:00
|
|
|
'debug'
|
|
|
|
);
|
|
|
|
|
|
|
|
# Get CAS session corresponding to ticket
|
2010-08-26 18:16:13 +02:00
|
|
|
if ( $urlType eq 'SERVICE' and !( $ticket =~ s/^ST-// ) ) {
|
2010-08-26 14:24:38 +02:00
|
|
|
$self->lmLog( "Provided ticket is not a service ticket (ST)",
|
|
|
|
'error' );
|
|
|
|
$self->returnCasServiceValidateError( 'INVALID_TICKET',
|
|
|
|
'Provided ticket is not a service ticket' );
|
|
|
|
}
|
2010-08-26 18:16:13 +02:00
|
|
|
elsif ( $urlType eq 'PROXY' and !( $ticket =~ s/^(P|S)T-// ) ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Provided ticket is not a service or proxy ticket ($1T)",
|
|
|
|
'error' );
|
|
|
|
$self->returnCasServiceValidateError( 'INVALID_TICKET',
|
|
|
|
'Provided ticket is not a service or proxy ticket' );
|
|
|
|
}
|
2010-08-26 14:24:38 +02:00
|
|
|
|
|
|
|
my $casServiceSession = $self->getCasSession($ticket);
|
|
|
|
|
|
|
|
unless ($casServiceSession) {
|
2010-08-26 18:16:13 +02:00
|
|
|
$self->lmLog( "$urlType ticket session $ticket not found",
|
|
|
|
'error' );
|
2010-08-26 14:24:38 +02:00
|
|
|
$self->returnCasServiceValidateError( 'INVALID_TICKET',
|
|
|
|
'Ticket not found' );
|
|
|
|
}
|
|
|
|
|
2010-08-26 18:16:13 +02:00
|
|
|
$self->lmLog( "$urlType ticket session $ticket found", 'debug' );
|
2010-08-26 14:24:38 +02:00
|
|
|
|
|
|
|
# Check service
|
|
|
|
unless ( $service eq $casServiceSession->{service} ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Submitted service $service does not match initial service "
|
|
|
|
. $casServiceSession->{service},
|
|
|
|
'error'
|
|
|
|
);
|
|
|
|
|
|
|
|
# CAS protocol: invalidate ticket if service is invalid
|
|
|
|
$self->deleteCasSession($casServiceSession);
|
|
|
|
|
|
|
|
$self->returnCasServiceValidateError( 'INVALID_SERVICE',
|
|
|
|
'Submitted service does not match initial service' );
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Submitted service $service match initial servce",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# Check renew
|
|
|
|
if ( $renew eq 'true' ) {
|
|
|
|
|
|
|
|
# We should check the ST was delivered with primary credentials
|
2010-08-30 11:24:04 +02:00
|
|
|
$self->lmLog( "Renew flag detected ", 'debug' );
|
|
|
|
|
|
|
|
unless ( $casServiceSession->{renew} ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Authentication renew requested, but not done in former authentication process",
|
|
|
|
'error'
|
|
|
|
);
|
|
|
|
untie %$casServiceSession;
|
|
|
|
$self->returnCasValidateError();
|
|
|
|
}
|
|
|
|
|
2010-08-26 14:24:38 +02:00
|
|
|
}
|
|
|
|
|
2010-08-26 18:16:13 +02:00
|
|
|
# Proxies (for PROXY VALIDATE only)
|
|
|
|
my $proxies = $casServiceSession->{proxies};
|
|
|
|
|
2010-08-26 14:24:38 +02:00
|
|
|
# Proxy granting ticket
|
|
|
|
if ($pgtUrl) {
|
|
|
|
|
2010-08-26 16:43:32 +02:00
|
|
|
# Create a proxy granting ticket
|
|
|
|
$self->lmLog(
|
|
|
|
"Create a CAS proxy granting ticket for service $service",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
my $casProxyGrantingSession = $self->getCasSession();
|
|
|
|
|
|
|
|
if ($casProxyGrantingSession) {
|
|
|
|
|
2010-08-26 18:16:13 +02:00
|
|
|
# PGT session
|
2010-08-26 16:43:32 +02:00
|
|
|
$casProxyGrantingSession->{type} = 'casProxyGranting';
|
|
|
|
$casProxyGrantingSession->{service} = $service;
|
|
|
|
$casProxyGrantingSession->{_cas_id} =
|
|
|
|
$casServiceSession->{_cas_id};
|
|
|
|
$casProxyGrantingSession->{_utime} =
|
|
|
|
$casServiceSession->{_utime};
|
|
|
|
|
2010-08-26 18:16:13 +02:00
|
|
|
# Trace proxies
|
2010-08-27 18:07:19 +02:00
|
|
|
$casProxyGrantingSession->{proxies} = (
|
|
|
|
$proxies
|
2010-08-26 18:16:13 +02:00
|
|
|
? $proxies . $self->{multiValuesSeparator} . $pgtUrl
|
2010-08-27 18:07:19 +02:00
|
|
|
: $pgtUrl
|
|
|
|
);
|
2010-08-26 18:16:13 +02:00
|
|
|
|
2010-08-26 16:43:32 +02:00
|
|
|
my $casProxyGrantingSessionID =
|
|
|
|
$casProxyGrantingSession->{_session_id};
|
|
|
|
my $casProxyGrantingTicket =
|
2010-08-26 18:16:13 +02:00
|
|
|
"PGT-" . $casProxyGrantingSessionID;
|
2010-08-26 16:43:32 +02:00
|
|
|
|
|
|
|
untie %$casProxyGrantingSession;
|
|
|
|
|
|
|
|
$self->lmLog(
|
|
|
|
"CAS proxy granting session $casProxyGrantingSessionID created",
|
|
|
|
'debug'
|
|
|
|
);
|
|
|
|
|
|
|
|
# Generate the proxy granting ticket IOU
|
|
|
|
my $tmpCasSession = $self->getCasSession();
|
|
|
|
|
|
|
|
if ($tmpCasSession) {
|
|
|
|
|
|
|
|
$casProxyGrantingTicketIOU =
|
|
|
|
"PGTIOU-" . $tmpCasSession->{_session_id};
|
|
|
|
$self->deleteCasSession($tmpCasSession);
|
2010-09-01 14:56:15 +02:00
|
|
|
$self->lmLog(
|
2010-08-26 16:43:32 +02:00
|
|
|
"Generate proxy granting ticket IOU $casProxyGrantingTicketIOU",
|
2010-09-01 14:56:15 +02:00
|
|
|
'debug'
|
|
|
|
);
|
2010-08-26 16:43:32 +02:00
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
# Request pgtUrl
|
|
|
|
if (
|
|
|
|
$self->callPgtUrl(
|
2010-08-26 16:43:32 +02:00
|
|
|
$pgtUrl,
|
|
|
|
$casProxyGrantingTicketIOU,
|
2010-09-01 14:56:15 +02:00
|
|
|
$casProxyGrantingTicket
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
$self->lmLog(
|
|
|
|
"Proxy granting URL $pgtUrl called with success",
|
|
|
|
'debug' );
|
|
|
|
}
|
|
|
|
else {
|
2010-08-26 16:43:32 +02:00
|
|
|
$self->lmLog(
|
|
|
|
"Error calling proxy granting URL $pgtUrl",
|
2010-09-01 14:56:15 +02:00
|
|
|
'warn' );
|
|
|
|
$casProxyGrantingTicketIOU = undef;
|
|
|
|
}
|
2010-08-26 16:43:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog(
|
|
|
|
"Error in proxy granting ticket management, bypass it",
|
|
|
|
'warn' );
|
|
|
|
}
|
2010-08-26 14:24:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Open local session
|
|
|
|
my $localSession =
|
|
|
|
$self->getApacheSession( $casServiceSession->{_cas_id}, 1 );
|
|
|
|
|
|
|
|
unless ($localSession) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Local session " . $casServiceSession->{_cas_id} . " notfound",
|
|
|
|
'error'
|
|
|
|
);
|
|
|
|
untie %$casServiceSession;
|
|
|
|
$self->returnCasServiceValidateError( 'INTERNAL_ERROR',
|
|
|
|
'No session associated to ticket' );
|
|
|
|
}
|
|
|
|
|
|
|
|
# Get username
|
2010-10-14 11:50:23 +02:00
|
|
|
my $username =
|
|
|
|
$localSession->{ $self->{casAttr} || $self->{whatToTrace} };
|
2010-08-26 14:24:38 +02:00
|
|
|
|
|
|
|
$self->lmLog( "Get username $username", 'debug' );
|
|
|
|
|
|
|
|
# Close sessions
|
|
|
|
untie %$casServiceSession;
|
|
|
|
untie %$localSession;
|
|
|
|
|
|
|
|
# Return success message
|
2010-08-26 16:43:32 +02:00
|
|
|
$self->returnCasServiceValidateSuccess( $username,
|
2010-08-26 18:16:13 +02:00
|
|
|
$casProxyGrantingTicketIOU, $proxies );
|
|
|
|
|
|
|
|
# We should not be there
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# 6. PROXY [CAS 2.0]
|
|
|
|
if ( $url =~ /\Q$cas_proxy_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS PROXY URL", 'debug' );
|
|
|
|
|
|
|
|
# GET parameters
|
|
|
|
my $pgt = $self->param('pgt');
|
|
|
|
my $targetService = $self->param('targetService');
|
|
|
|
|
|
|
|
# Required parameters: pgt and targetService
|
|
|
|
unless ( $pgt and $targetService ) {
|
|
|
|
$self->lmLog( "Pgt and TargetService parameters required",
|
|
|
|
'error' );
|
|
|
|
$self->returnCasProxyError( 'INVALID_REQUEST',
|
|
|
|
'Missing mandatory parameters (pgt, targetService)' );
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog(
|
|
|
|
"Get proxy request with ticket $pgt for service $targetService",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# Get CAS session corresponding to ticket
|
|
|
|
unless ( $pgt =~ s/^PGT-// ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Provided ticket is not a proxy granting ticket (PGT)",
|
|
|
|
'error' );
|
|
|
|
$self->returnCasProxyError( 'BAD_PGT',
|
|
|
|
'Provided ticket is not a proxy granting ticket' );
|
|
|
|
}
|
|
|
|
|
|
|
|
my $casProxyGrantingSession = $self->getCasSession($pgt);
|
|
|
|
|
|
|
|
unless ($casProxyGrantingSession) {
|
|
|
|
$self->lmLog( "Proxy granting ticket session $pgt not found",
|
|
|
|
'error' );
|
|
|
|
$self->returnCasProxyError( 'BAD_PGT', 'Ticket not found' );
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Proxy granting session $pgt found", 'debug' );
|
|
|
|
|
|
|
|
# Create a proxy ticket
|
|
|
|
$self->lmLog( "Create a CAS proxy ticket for service $targetService",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
my $casProxySession = $self->getCasSession();
|
|
|
|
|
|
|
|
unless ($casProxySession) {
|
|
|
|
$self->lmLog( "Unable to create CAS proxy session", 'error' );
|
|
|
|
$self->returnCasProxyError( 'INTERNAL_ERROR',
|
|
|
|
'Error in proxy session management' );
|
|
|
|
}
|
|
|
|
|
|
|
|
$casProxySession->{type} = 'casProxy';
|
|
|
|
$casProxySession->{service} = $targetService;
|
|
|
|
$casProxySession->{_cas_id} = $casProxyGrantingSession->{_cas_id};
|
|
|
|
$casProxySession->{_utime} = $casProxyGrantingSession->{_utime};
|
|
|
|
$casProxySession->{proxies} = $casProxyGrantingSession->{proxies};
|
|
|
|
|
|
|
|
my $casProxySessionID = $casProxySession->{_session_id};
|
|
|
|
my $casProxyTicket = "PT-" . $casProxySessionID;
|
|
|
|
|
|
|
|
# Close sessions
|
|
|
|
untie %$casProxySession;
|
|
|
|
untie %$casProxyGrantingSession;
|
|
|
|
|
|
|
|
$self->lmLog( "CAS proxy session $casProxySessionID created", 'debug' );
|
|
|
|
|
|
|
|
# Return success message
|
|
|
|
$self->returnCasProxySuccess($casProxyTicket);
|
2010-08-26 14:24:38 +02:00
|
|
|
|
|
|
|
# We should not be there
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-08-26 10:42:28 +02:00
|
|
|
return PE_OK;
|
2010-08-23 17:47:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
## @apmethod int issuerForAuthUser()
|
2010-08-23 18:41:38 +02:00
|
|
|
# Manage CAS request for unauthenticated user
|
2010-08-23 17:47:53 +02:00
|
|
|
# @return Lemonldap::NG::Portal error code
|
|
|
|
sub issuerForAuthUser {
|
2010-09-01 14:56:15 +02:00
|
|
|
my $self = shift;
|
2010-08-23 18:41:38 +02:00
|
|
|
|
|
|
|
# CAS URLs
|
2011-12-05 16:58:20 +01:00
|
|
|
my $cas_login_url = '/cas/login';
|
|
|
|
my $cas_logout_url = '/cas/logout';
|
|
|
|
my $cas_validate_url = '/cas/validate';
|
|
|
|
my $cas_serviceValidate_url = '/cas/serviceValidate';
|
|
|
|
my $cas_proxyValidate_url = '/cas/proxyValidate';
|
|
|
|
my $cas_proxy_url = '/cas/proxy';
|
2010-08-25 16:23:45 +02:00
|
|
|
|
|
|
|
# Called URL
|
2011-12-05 16:58:20 +01:00
|
|
|
my $url = $self->url( -absolute => 1 );
|
2010-08-25 16:23:45 +02:00
|
|
|
|
|
|
|
# Session ID
|
|
|
|
my $session_id = $self->{sessionInfo}->{_session_id} || $self->{id};
|
|
|
|
|
2010-08-25 17:57:21 +02:00
|
|
|
# Session creation timestamp
|
|
|
|
my $time = $self->{sessionInfo}->{_utime} || time();
|
|
|
|
|
2010-08-25 16:23:45 +02:00
|
|
|
# 1. LOGIN
|
|
|
|
if ( $url =~ /\Q$cas_login_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS LOGIN URL", 'debug' );
|
|
|
|
|
|
|
|
# GET parameters
|
|
|
|
my $service = $self->getHiddenFormValue('service')
|
|
|
|
|| $self->param('service');
|
|
|
|
my $renew = $self->getHiddenFormValue('renew') || $self->param('renew');
|
|
|
|
my $gateway = $self->getHiddenFormValue('gateway')
|
|
|
|
|| $self->param('gateway');
|
2011-09-15 11:42:25 +02:00
|
|
|
my $casServiceTicket;
|
2010-08-25 16:23:45 +02:00
|
|
|
|
|
|
|
# Renew
|
2010-08-26 10:42:28 +02:00
|
|
|
if ( $renew eq 'true' ) {
|
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
# Authentication must be replayed
|
2010-08-30 10:56:16 +02:00
|
|
|
$self->lmLog( "Authentication renew requested", 'debug' );
|
|
|
|
$self->{updateSession} = 1;
|
|
|
|
$self->{error} = $self->_subProcess(
|
|
|
|
qw(issuerDBInit authInit issuerForUnAuthUser extractFormInfo
|
|
|
|
userDBInit getUser setAuthSessionInfo setSessionInfo
|
2010-10-21 12:28:47 +02:00
|
|
|
setMacros setLocalGroups setGroups setPersistentSessionInfo
|
|
|
|
authenticate store authFinish)
|
2010-08-30 10:56:16 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
# Return error if any
|
|
|
|
if ( $self->{error} > 0 ) {
|
|
|
|
$self->lmLog( "Error in authentication renew process",
|
|
|
|
'error' );
|
|
|
|
return $self->{error};
|
|
|
|
}
|
2010-08-25 16:23:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# If no service defined, exit
|
|
|
|
unless ( defined $service ) {
|
|
|
|
$self->lmLog( "No service defined in CAS URL", 'debug' );
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-15 11:42:25 +02:00
|
|
|
# Check access on the service
|
|
|
|
my $casAccessControlPolicy = $self->{casAccessControlPolicy};
|
|
|
|
|
|
|
|
if ( $casAccessControlPolicy =~ /^(error|faketicket)$/i ) {
|
|
|
|
$self->lmLog( "CAS access control requested on service $service",
|
2010-08-30 11:24:04 +02:00
|
|
|
'debug' );
|
|
|
|
|
2011-09-15 11:42:25 +02:00
|
|
|
if ( $self->_grant($service) ) {
|
|
|
|
$self->lmLog( "CAS service $service access allowed", 'debug' );
|
|
|
|
}
|
2010-08-25 16:23:45 +02:00
|
|
|
|
2011-09-15 11:42:25 +02:00
|
|
|
else {
|
|
|
|
$self->lmLog( "CAS service $service access not allowed",
|
|
|
|
'error' );
|
2010-08-25 16:23:45 +02:00
|
|
|
|
2011-09-15 11:42:25 +02:00
|
|
|
if ( $casAccessControlPolicy =~ /^(error)$/i ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Return error instead of redirecting user on CAS service",
|
|
|
|
'debug'
|
|
|
|
);
|
|
|
|
return PE_CAS_SERVICE_NOT_ALLOWED;
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
$self->lmLog(
|
|
|
|
"Redirect user on CAS service with a fake ticket",
|
|
|
|
'debug' );
|
|
|
|
$casServiceTicket = "ST-F4K3T1CK3T";
|
|
|
|
}
|
|
|
|
}
|
2010-08-30 10:56:16 +02:00
|
|
|
}
|
2010-08-25 16:23:45 +02:00
|
|
|
|
2011-09-15 11:42:25 +02:00
|
|
|
unless ($casServiceTicket) {
|
2010-08-25 16:23:45 +02:00
|
|
|
|
2011-09-15 11:42:25 +02:00
|
|
|
# Check last authentication time to decide if
|
|
|
|
# the authentication is recent or not
|
|
|
|
my $casRenewFlag = 0;
|
|
|
|
my $last_authn_utime = $self->{sessionInfo}->{_lastAuthnUTime} || 0;
|
|
|
|
if (
|
|
|
|
time() - $last_authn_utime < $self->{portalForceAuthnInterval} )
|
|
|
|
{
|
|
|
|
$self->lmLog(
|
|
|
|
"Authentication is recent, will set CAS renew flag to true",
|
|
|
|
'debug'
|
|
|
|
);
|
|
|
|
$casRenewFlag = 1;
|
|
|
|
}
|
2010-08-25 16:23:45 +02:00
|
|
|
|
2011-09-15 11:42:25 +02:00
|
|
|
# Create a service ticket
|
|
|
|
$self->lmLog( "Create a CAS service ticket for service $service",
|
|
|
|
'debug' );
|
2010-08-25 16:23:45 +02:00
|
|
|
|
2011-09-15 11:42:25 +02:00
|
|
|
my $casServiceSession = $self->getCasSession();
|
|
|
|
|
|
|
|
unless ($casServiceSession) {
|
|
|
|
$self->lmLog( "Unable to create CAS session", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$casServiceSession->{type} = 'casService';
|
|
|
|
$casServiceSession->{service} = $service;
|
|
|
|
$casServiceSession->{renew} = $casRenewFlag;
|
|
|
|
$casServiceSession->{_cas_id} = $session_id;
|
|
|
|
$casServiceSession->{_utime} = $time;
|
|
|
|
|
|
|
|
my $casServiceSessionID = $casServiceSession->{_session_id};
|
|
|
|
$casServiceTicket = "ST-" . $casServiceSessionID;
|
|
|
|
|
|
|
|
untie %$casServiceSession;
|
|
|
|
|
|
|
|
$self->lmLog( "CAS service session $casServiceSessionID created",
|
|
|
|
'debug' );
|
|
|
|
}
|
2010-08-25 16:23:45 +02:00
|
|
|
|
|
|
|
# Redirect to service
|
2010-09-23 15:19:25 +02:00
|
|
|
my $service_url = $service;
|
|
|
|
$service_url .= (
|
2010-09-23 18:41:39 +02:00
|
|
|
$service =~ /\?/
|
2010-09-23 15:19:25 +02:00
|
|
|
? '&ticket=' . $casServiceTicket
|
|
|
|
: '?ticket=' . $casServiceTicket
|
2010-08-25 16:23:45 +02:00
|
|
|
);
|
|
|
|
|
2010-08-25 17:57:21 +02:00
|
|
|
$self->lmLog( "Redirect user to $service_url", 'debug' );
|
|
|
|
|
2010-08-25 16:23:45 +02:00
|
|
|
$self->{urldc} = $service_url;
|
|
|
|
|
|
|
|
return $self->_subProcess(qw(autoRedirect));
|
|
|
|
}
|
2010-08-23 18:41:38 +02:00
|
|
|
|
2010-08-25 17:33:33 +02:00
|
|
|
# 2. LOGOUT
|
|
|
|
if ( $url =~ /\Q$cas_logout_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS LOGOUT URL", 'debug' );
|
|
|
|
|
|
|
|
# GET parameters
|
|
|
|
my $logout_url = $self->param('url');
|
|
|
|
|
|
|
|
# Delete linked CAS sessions
|
2010-08-26 10:42:28 +02:00
|
|
|
$self->deleteCasSecondarySessions($session_id);
|
2010-08-25 17:33:33 +02:00
|
|
|
|
|
|
|
# Delete local session
|
|
|
|
unless (
|
|
|
|
$self->_deleteSession( $self->getApacheSession( $session_id, 1 ) ) )
|
|
|
|
{
|
|
|
|
$self->lmLog( "Fail to delete session $session_id ", 'error' );
|
|
|
|
}
|
|
|
|
|
2010-08-27 18:07:19 +02:00
|
|
|
if ($logout_url) {
|
|
|
|
|
|
|
|
# Display a link to the provided URL
|
|
|
|
$self->lmLog( "Logout URL $logout_url will be displayed", 'debug' );
|
|
|
|
|
|
|
|
$self->info(
|
|
|
|
"<h3>"
|
|
|
|
. &Lemonldap::NG::Portal::_i18n::msg( PM_BACKTOCASURL,
|
|
|
|
$ENV{HTTP_ACCEPT_LANGUAGE} )
|
|
|
|
. "</h3>"
|
|
|
|
);
|
|
|
|
$self->info("<p><a href=\"$logout_url\">$logout_url</a></p>");
|
|
|
|
$self->{activeTimer} = 0;
|
|
|
|
|
|
|
|
return PE_CONFIRM;
|
|
|
|
}
|
|
|
|
|
2010-08-25 17:33:33 +02:00
|
|
|
return PE_LOGOUT_OK;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# 3. VALIDATE [CAS 1.0]
|
|
|
|
if ( $url =~ /\Q$cas_validate_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS VALIDATE URL", 'debug' );
|
|
|
|
|
2010-08-25 17:57:21 +02:00
|
|
|
# This URL must not be called by authenticated users
|
2010-08-25 17:33:33 +02:00
|
|
|
$self->lmLog(
|
|
|
|
"CAS VALIDATE URL called by authenticated user, ignore it",
|
|
|
|
'info' );
|
|
|
|
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-26 14:24:38 +02:00
|
|
|
# 4. SERVICE VALIDATE [CAS 2.0]
|
|
|
|
if ( $url =~ /\Q$cas_serviceValidate_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS SERVICE VALIDATE URL",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# This URL must not be called by authenticated users
|
|
|
|
$self->lmLog(
|
|
|
|
"CAS SERVICE VALIDATE URL called by authenticated user, ignore it",
|
|
|
|
'info'
|
|
|
|
);
|
|
|
|
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-26 18:16:13 +02:00
|
|
|
# 5. PROXY VALIDATE [CAS 2.0]
|
|
|
|
if ( $url =~ /\Q$cas_proxyValidate_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS PROXY VALIDATE URL",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# This URL must not be called by authenticated users
|
|
|
|
$self->lmLog(
|
|
|
|
"CAS PROXY VALIDATE URL called by authenticated user, ignore it",
|
|
|
|
'info' );
|
|
|
|
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
# 6. PROXY [CAS 2.0]
|
|
|
|
if ( $url =~ /\Q$cas_proxy_url\E/io ) {
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an CAS PROXY URL", 'debug' );
|
|
|
|
|
|
|
|
# This URL must not be called by authenticated users
|
|
|
|
$self->lmLog( "CAS PROXY URL called by authenticated user, ignore it",
|
|
|
|
'info' );
|
|
|
|
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-26 10:42:28 +02:00
|
|
|
return PE_OK;
|
2010-08-23 17:47:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
## @apmethod int issuerLogout()
|
2010-08-25 16:23:45 +02:00
|
|
|
# Destroy linked CAS sessions
|
2010-08-23 17:47:53 +02:00
|
|
|
# @return Lemonldap::NG::Portal error code
|
|
|
|
sub issuerLogout {
|
2010-08-23 18:41:38 +02:00
|
|
|
my $self = shift;
|
2010-08-25 16:23:45 +02:00
|
|
|
|
2010-08-26 10:42:28 +02:00
|
|
|
# Session ID
|
|
|
|
my $session_id = $self->{sessionInfo}->{_session_id} || $self->{id};
|
|
|
|
|
|
|
|
# Delete linked CAS sessions
|
|
|
|
$self->deleteCasSecondarySessions($session_id);
|
2010-08-25 16:23:45 +02:00
|
|
|
|
2010-08-26 10:42:28 +02:00
|
|
|
return PE_OK;
|
2010-08-23 17:47:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|
|
|
|
|
|
|
|
__END__
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
=encoding utf8
|
|
|
|
|
|
|
|
Lemonldap::NG::Portal::IssuerDBCAS - CAS IssuerDB for LemonLDAP::NG
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
CAS Issuer implementation in LemonLDAP::NG
|
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
2010-10-26 12:59:22 +02:00
|
|
|
L<Lemonldap::NG::Portal>,
|
|
|
|
L<http://www.jasig.org/cas/protocol>
|
2010-08-23 17:47:53 +02:00
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
2010-08-23 18:41:38 +02:00
|
|
|
Clement OUDOT, E<lt>clement@oodo.netE<gt>
|
2010-08-23 17:47:53 +02:00
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
|
|
|
|
Copyright (C) 2010 by Clement OUDOT
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.10.0 or,
|
|
|
|
at your option, any later version of Perl 5 you may have available.
|
|
|
|
|
|
|
|
=cut
|