lemonldap-ng/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBCAS.pm

549 lines
16 KiB
Perl
Raw Normal View History

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;
our @ISA = qw(Lemonldap::NG::Portal::_CAS);
2010-08-23 17:47:53 +02:00
our $VERSION = '0.01';
## @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;
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
2010-08-25 16:23:45 +02:00
my $portal = $self->{portal};
$portal =~ s/\/$//;
2010-08-23 18:41:38 +02:00
# CAS URLs
2010-08-25 16:23:45 +02:00
my $cas_login_url = $portal . '/cas/login';
my $cas_logout_url = $portal . '/cas/logout';
my $cas_validate_url = $portal . '/cas/validate';
my $cas_serviceValidate_url = $portal . '/cas/serviceValidate';
my $cas_proxyValidate_url = $portal . '/cas/proxyValidate';
my $cas_proxy_url = $portal . '/cas/proxy';
# Called URL
my $url = $self->url();
# 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
# Authentication must use non-interactive mean
if ( $gateway eq 'true' ) {
# TODO
$self->lmLog( "Gateway authentication not managed", 'warn' );
}
}
# 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) {
# We should display a link to the provided URL
# TODO
$self->lmLog( "Return URL not managed", 'warn' );
}
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();
}
$self->lmLog(
"Get validate request with ticket $ticket for service $service",
'debug' );
# Get CAS session corresponding to ticket
unless ( $ticket =~ s/^ST-// ) {
$self->lmLog( "Provided ticket is not a service ticket (ST)",
'error' );
$self->returnCasValidateError();
}
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
# TODO
$self->lmLog( "Renew parameter not managed", 'warn' );
}
# 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->returnCasValidateError();
2010-08-25 16:23:45 +02:00
}
# Get username
my $username = $localSession->{ $self->{whatToTrace} };
$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]
if ( $url =~ /\Q$cas_serviceValidate_url\E/io ) {
$self->lmLog( "URL $url detected as an CAS SERVICE VALIDATE URL",
'debug' );
# GET parameters
my $service = $self->param('service');
my $ticket = $self->param('ticket');
my $pgtUrl = $self->param('pgtUrl');
my $renew = $self->param('renew');
# 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(
"Get service validate request with ticket $ticket for service $service",
'debug'
);
# Get CAS session corresponding to ticket
unless ( $ticket =~ s/^ST-// ) {
$self->lmLog( "Provided ticket is not a service ticket (ST)",
'error' );
$self->returnCasServiceValidateError( 'INVALID_TICKET',
'Provided ticket is not a service ticket' );
}
my $casServiceSession = $self->getCasSession($ticket);
unless ($casServiceSession) {
$self->lmLog( "Service ticket session $ticket not found", 'error' );
$self->returnCasServiceValidateError( 'INVALID_TICKET',
'Ticket not found' );
}
$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'
);
# 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
# TODO
$self->lmLog( "Renew parameter not managed", 'warn' );
}
# Proxy granting ticket
if ($pgtUrl) {
# Create a proxy granting ticket
$self->lmLog(
"Create a CAS proxy granting ticket for service $service",
'debug' );
my $casProxyGrantingSession = $self->getCasSession();
if ($casProxyGrantingSession) {
$casProxyGrantingSession->{type} = 'casProxyGranting';
$casProxyGrantingSession->{service} = $service;
$casProxyGrantingSession->{_cas_id} =
$casServiceSession->{_cas_id};
$casProxyGrantingSession->{_utime} =
$casServiceSession->{_utime};
my $casProxyGrantingSessionID =
$casProxyGrantingSession->{_session_id};
my $casProxyGrantingTicket =
"TGT-" . $casProxyGrantingSessionID;
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);
$self->lmLog(
"Generate proxy granting ticket IOU $casProxyGrantingTicketIOU",
'debug'
);
2010-08-26 14:24:38 +02:00
# Request pgtUrl
if (
$self->callPgtUrl(
$pgtUrl,
$casProxyGrantingTicketIOU,
$casProxyGrantingTicket
)
)
{
$self->lmLog(
"Proxy granting URL $pgtUrl called with success",
'debug' );
}
else {
$self->lmLog(
"Error calling proxy granting URL $pgtUrl",
'warn' );
$casProxyGrantingTicketIOU = undef;
}
}
}
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
my $username = $localSession->{ $self->{whatToTrace} };
$self->lmLog( "Get username $username", 'debug' );
# Close sessions
untie %$casServiceSession;
untie %$localSession;
# Return success message
$self->returnCasServiceValidateSuccess( $username,
$casProxyGrantingTicketIOU );
2010-08-26 14:24:38 +02:00
# We should not be there
return PE_ERROR;
}
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 {
my $self = shift;
2010-08-23 18:41:38 +02:00
2010-08-25 16:23:45 +02:00
my $portal = $self->{portal};
$portal =~ s/\/$//;
2010-08-23 18:41:38 +02:00
# CAS URLs
2010-08-25 16:23:45 +02:00
my $cas_login_url = $portal . '/cas/login';
my $cas_logout_url = $portal . '/cas/logout';
my $cas_validate_url = $portal . '/cas/validate';
my $cas_serviceValidate_url = $portal . '/cas/serviceValidate';
my $cas_proxyValidate_url = $portal . '/cas/proxyValidate';
my $cas_proxy_url = $portal . '/cas/proxy';
# Called URL
my $url = $self->url();
# Session ID
my $session_id = $self->{sessionInfo}->{_session_id} || $self->{id};
# 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');
# Renew
if ( $renew eq 'true' ) {
2010-08-25 16:23:45 +02:00
# Authentication must be replayed
# TODO
$self->lmLog( "Authentication renewal not managed", 'warn' );
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;
}
# Create a service ticket
$self->lmLog( "Create a CAS service ticket for service $service",
'debug' );
my $casServiceSession = $self->getCasSession();
return PE_ERROR unless $casServiceSession;
$casServiceSession->{type} = 'casService';
$casServiceSession->{service} = $service;
$casServiceSession->{_cas_id} = $session_id;
$casServiceSession->{_utime} = $time;
2010-08-25 16:23:45 +02:00
my $casServiceSessionID = $casServiceSession->{_session_id};
my $casServiceTicket = "ST-" . $casServiceSessionID;
untie %$casServiceSession;
$self->lmLog( "CAS service session $casServiceSessionID created",
'debug' );
# Redirect to service
my $service_url = (
$service =~ /\?/
? $service .= '&ticket=' . $casServiceTicket
: $service .= '?ticket=' . $casServiceTicket
);
$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
# 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) {
# We should display a link to the provided URL
# TODO
}
# Delete linked CAS sessions
$self->deleteCasSecondarySessions($session_id);
# Delete local session
unless (
$self->_deleteSession( $self->getApacheSession( $session_id, 1 ) ) )
{
$self->lmLog( "Fail to delete session $session_id ", 'error' );
}
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' );
# This URL must not be called by authenticated users
$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;
}
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
# 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
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
L<Lemonldap::NG::Portal>
http://www.jasig.org/cas/protocol
=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