2016-12-20 12:53:33 +01:00
|
|
|
package Lemonldap::NG::Portal::Auth::CAS;
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
use Mouse;
|
|
|
|
use URI::Escape;
|
2017-04-11 19:05:00 +02:00
|
|
|
use Lemonldap::NG::Common::FormEncode;
|
2016-12-20 11:43:22 +01:00
|
|
|
use Lemonldap::NG::Portal::Main::Constants qw(
|
|
|
|
PE_ERROR
|
|
|
|
PE_OK
|
|
|
|
PE_REDIRECT
|
|
|
|
PE_SENDRESPONSE
|
|
|
|
);
|
|
|
|
|
|
|
|
our $VERSION = '2.0.0';
|
|
|
|
|
2016-12-20 12:53:33 +01:00
|
|
|
extends 'Lemonldap::NG::Portal::Auth::Base', 'Lemonldap::NG::Portal::Lib::CAS';
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
# PROPERTIES
|
|
|
|
|
|
|
|
# Act as a proxy if proxied services configured
|
|
|
|
has proxy => (
|
|
|
|
is => 'rw',
|
2017-03-27 18:51:18 +02:00
|
|
|
lazy => 1,
|
2016-12-20 11:43:22 +01:00
|
|
|
builder => sub {
|
|
|
|
return
|
2016-12-29 07:25:07 +01:00
|
|
|
ref( $_[0]->conf->{CAS_proxiedServices} ) eq 'HASH'
|
|
|
|
? ( %{ $_[0]->conf->{CAS_proxiedServices} } ? 1 : 0 )
|
2016-12-20 11:43:22 +01:00
|
|
|
: 0;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2017-03-28 20:23:50 +02:00
|
|
|
has proxyUrl => ( is => 'rw' );
|
|
|
|
has pgtId => ( is => 'rw' );
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
# INITIALIZATION
|
|
|
|
|
|
|
|
sub init {
|
|
|
|
my ($self) = @_;
|
2017-03-28 20:23:50 +02:00
|
|
|
|
|
|
|
# TODO: loop over CAS servers
|
|
|
|
|
2016-12-21 06:32:38 +01:00
|
|
|
return 1;
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# RUNNING METHODS
|
|
|
|
|
|
|
|
sub extractFormInfo {
|
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
|
|
|
|
# Local URL
|
2016-12-22 09:40:50 +01:00
|
|
|
my $local_url = $self->p->fullUrl($req);
|
2016-12-20 11:43:22 +01:00
|
|
|
|
2017-03-28 20:23:50 +02:00
|
|
|
# TODO: create a CAS state session
|
2016-12-20 11:43:22 +01:00
|
|
|
# Add request state parameters
|
|
|
|
if ( $req->datas->{_url} ) {
|
2017-04-11 19:05:00 +02:00
|
|
|
$local_url .= ( $local_url =~ /\?/ ? '&' : '?' )
|
|
|
|
. build_urlencoded( url => $req->datas->{_url} );
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
2017-01-12 18:44:33 +01:00
|
|
|
if ( $self->conf->{authChoiceParam}
|
|
|
|
and my $tmp = $req->param( $self->conf->{authChoiceParam} ) )
|
|
|
|
{
|
2017-04-11 19:05:00 +02:00
|
|
|
$local_url .= ( $local_url =~ /\?/ ? '&' : '?' )
|
|
|
|
. build_urlencoded( $self->conf->{authChoiceParam} => $tmp );
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Forward hidden fields
|
|
|
|
if ( $req->{portalHiddenFormValues}
|
|
|
|
and %{ $req->{portalHiddenFormValues} } )
|
|
|
|
{
|
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Add hidden values to CAS redirect URL\n");
|
2017-04-11 19:05:00 +02:00
|
|
|
$local_url .= ( $local_url =~ /\?/ ? '&' : '?' )
|
|
|
|
. build_urlencoded( %{ $req->{portalHiddenFormValues} } );
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( $self->proxy ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("CAS: Proxy mode activated");
|
2016-12-22 09:40:50 +01:00
|
|
|
my $proxy_url = $self->p->fullUrl($req) . '?casProxy=1';
|
2016-12-20 11:43:22 +01:00
|
|
|
|
2017-01-12 18:44:33 +01:00
|
|
|
if ( $self->conf->{authChoiceParam}
|
|
|
|
and my $tmp = $req->param( $self->conf->{authChoiceParam} ) )
|
|
|
|
{
|
2016-12-20 11:43:22 +01:00
|
|
|
$proxy_url .= '&' . $self->conf->{authChoiceParam} . "=$tmp";
|
|
|
|
}
|
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("CAS Proxy URL: $proxy_url");
|
2016-12-20 11:43:22 +01:00
|
|
|
|
2017-03-28 20:23:50 +02:00
|
|
|
$self->proxyUrl = $proxy_url;
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Catch proxy callback
|
|
|
|
if ( $req->param('casProxy') ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("CAS: Proxy callback detected");
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
my $pgtIou = $req->param('pgtIou');
|
|
|
|
my $pgtId = $req->param('pgtId');
|
|
|
|
|
|
|
|
if ( $pgtIou and $pgtId ) {
|
|
|
|
|
|
|
|
# Store pgtId and pgtIou
|
2017-03-28 20:23:50 +02:00
|
|
|
my $pgtSessionId = $self->storePGT( $pgtIou, $pgtId );
|
|
|
|
unless ($pgtSessionId) {
|
2017-02-19 12:51:58 +01:00
|
|
|
$self->userLogger->error(
|
2017-03-28 20:23:50 +02:00
|
|
|
"CAS: Unable to store pgtIou $pgtIou and pgtId $pgtId");
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug(
|
2017-03-28 20:23:50 +02:00
|
|
|
"CAS: Store pgtIou $pgtIou and pgtId $pgtId in session $pgtSessionId"
|
|
|
|
);
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Exit
|
|
|
|
$req->response( [ 200, [ 'Content-Length' => 0 ], [] ] );
|
|
|
|
return PE_SENDRESPONSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Build login URL
|
2017-03-28 20:23:50 +02:00
|
|
|
my $login_url = $self->getServerLoginURL($local_url);
|
2016-12-29 07:25:07 +01:00
|
|
|
$login_url .= '&renew=true' if $self->conf->{CAS_renew};
|
|
|
|
$login_url .= '&gateway=true' if $self->conf->{CAS_gateway};
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
# Check Service Ticket
|
|
|
|
my $ticket = $req->param('ticket');
|
|
|
|
|
|
|
|
# Unless a ticket has been found, we redirect the user
|
|
|
|
unless ($ticket) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("CAS: Redirect user to $login_url");
|
2016-12-20 11:43:22 +01:00
|
|
|
$req->{urldc} = $login_url;
|
|
|
|
$req->steps( [] );
|
|
|
|
return PE_REDIRECT;
|
|
|
|
}
|
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("CAS: Service Ticket received: $ticket");
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
# Ticket found, try to validate it
|
2017-03-29 21:43:10 +02:00
|
|
|
$local_url =~ s/ticket=[^&]+//;
|
|
|
|
$local_url =~ s/\?$//;
|
2017-04-11 19:05:02 +02:00
|
|
|
( $req->{user}, $req->datas->{casAttr} ) =
|
|
|
|
$self->validateST( $local_url, $ticket );
|
|
|
|
unless ( $req->{user} ) {
|
2017-03-28 20:23:50 +02:00
|
|
|
$self->userLogger->error("CAS: Unable to validate ST $ticket");
|
2016-12-20 11:43:22 +01:00
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
else {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("CAS: User $req->{user} found");
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Request proxy tickets for proxied services
|
|
|
|
if ( $self->proxy ) {
|
|
|
|
|
|
|
|
# Check we received a PGT
|
2017-03-28 20:23:50 +02:00
|
|
|
my $pgtId = $self->pgtId;
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
unless ($pgtId) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error(
|
|
|
|
"CAS: Proxy mode activated, but no PGT received");
|
2016-12-20 11:43:22 +01:00
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Get a proxy ticket for each proxied service
|
2016-12-29 07:25:07 +01:00
|
|
|
foreach ( keys %{ $self->conf->{CAS_proxiedServices} } ) {
|
|
|
|
my $service = $self->conf->{CAS_proxiedServices}->{$_};
|
2017-03-28 20:23:50 +02:00
|
|
|
my $pt = $self->retrievePT($service);
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
unless ($pt) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error(
|
|
|
|
"CAS: No proxy ticket recevied for service $service");
|
2016-12-20 11:43:22 +01:00
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug(
|
|
|
|
"CAS: Received proxy ticket $pt for service $service");
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
# Store it in session
|
|
|
|
$req->{sessionInfo}->{ '_casPT' . $_ } = $pt;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub authenticate {
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set authenticationLevel.
|
|
|
|
sub setAuthSessionInfo {
|
|
|
|
my ( $self, $req ) = @_;
|
2016-12-29 07:25:07 +01:00
|
|
|
$req->{sessionInfo}->{authenticationLevel} = $self->conf->{CAS_authnLevel};
|
2016-12-20 11:43:22 +01:00
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub authLogout {
|
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
|
|
|
|
# Build CAS logout URL
|
2016-12-22 09:40:50 +01:00
|
|
|
my $logout_url =
|
2017-03-28 20:23:50 +02:00
|
|
|
$self->getServerLogoutURL( uri_escape( $self->p->fullUrl($req) ) );
|
2016-12-20 11:43:22 +01:00
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Build CAS logout URL: $logout_url");
|
2016-12-20 11:43:22 +01:00
|
|
|
|
|
|
|
# Register CAS logout URL in logoutServices
|
|
|
|
$req->datas->{logoutServices}->{CASserver} = $logout_url;
|
|
|
|
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub getDisplayType {
|
|
|
|
return "logo";
|
|
|
|
}
|
2016-12-20 12:53:33 +01:00
|
|
|
|
|
|
|
1;
|