lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/CAS.pm

215 lines
5.5 KiB
Perl
Raw Normal View History

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',
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
$local_url =~ s/ticket=[^&]+//;
$local_url =~ s/\?$//;
( $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;