From b721763e23d94a5a11cf6caf86e73dd53128f0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Oudot?= Date: Thu, 26 Aug 2010 12:24:38 +0000 Subject: [PATCH] Manage CAS service validate URL (#101) --- .../lib/Lemonldap/NG/Portal/IssuerDBCAS.pm | 121 ++++++++++++++++++ .../lib/Lemonldap/NG/Portal/_CAS.pm | 101 +++++++++++++-- 2 files changed, 211 insertions(+), 11 deletions(-) diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBCAS.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBCAS.pm index affe16df3..389204b63 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBCAS.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/IssuerDBCAS.pm @@ -175,6 +175,112 @@ sub issuerForUnAuthUser { return PE_ERROR; } + # 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'); + + # 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) { + + # Request pgtUrl + # TODO + $self->lmLog( "PgtUrl 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->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); + + # We should not be there + return PE_ERROR; + } + return PE_OK; } @@ -306,6 +412,21 @@ sub issuerForAuthUser { return PE_OK; } + # 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; } diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_CAS.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_CAS.pm index 47e271960..4e0c4e90d 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_CAS.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_CAS.pm @@ -41,6 +41,8 @@ sub getCasSession { sub returnCasValidateError { my ($self) = splice @_; + $self->lmLog( "Return CAS validate error", 'debug' ); + print $self->header(); print "no\n\n"; @@ -54,12 +56,58 @@ sub returnCasValidateError { sub returnCasValidateSuccess { my ( $self, $username ) = splice @_; + $self->lmLog( "Return CAS validate success with username $username", + 'debug' ); + print $self->header(); print "yes\n$username\n"; $self->quit(); } +## @method void returnCasServiceValidateError(string code, string text) +# Return an error for CAS SERVICE VALIDATE request +# @param code CAS error code +# @param text Error text +# @return nothing +sub returnCasServiceValidateError { + my ( $self, $code, $text ) = splice @_; + + $code ||= 'INTERNAL_ERROR'; + $text ||= 'No description provided'; + + $self->lmLog( "Return CAS service validate error $code ($text)", 'debug' ); + + print $self->header( -type => 'application/xml' ); + print "\n"; + print "\t\n"; + print "\t\t$text\n"; + print "\t\n"; + print "\n"; + + $self->quit(); +} + +## @method void returnCasServiceValidateSuccess(string username) +# Return success for CAS SERVICE VALIDATE request +# @param username User name +# @return nothing +sub returnCasServiceValidateSuccess { + my ( $self, $username ) = splice @_; + + $self->lmLog( "Return CAS service validate success with username $username", + 'debug' ); + + print $self->header( -type => 'application/xml' ); + print "\n"; + print "\t\n"; + print "\t\t$username\n"; + print "\t\n"; + print "\n"; + + $self->quit(); +} + ## @method boolean deleteCasSecondarySessions(string session_id) # Find and delete CAS sessions bounded to a primary session # @param session_id Primary session ID @@ -83,17 +131,7 @@ sub deleteCasSecondarySessions { my $casSessionInfo = $self->getCasSession($cas_session); # Delete session - eval { tied(%$casSessionInfo)->delete() }; - - if ($@) { - $self->lmLog( "Unable to delete CAS session $cas_session: $@", - 'error' ); - $result = 0; - } - else { - $self->lmLog( "CAS session $cas_session deleted", 'debug' ); - } - + $result = $self->deleteCasSession($casSessionInfo); } } else { @@ -105,6 +143,35 @@ sub deleteCasSecondarySessions { } +## @method boolean deleteCasSession(hashref session) +# Delete an opened CAS session +# @param session Tied session object +# @return result +sub deleteCasSession { + my ( $self, $session ) = splice @_; + + # Check session object + unless ( ref($session) eq 'HASH' ) { + $self->lmLog( "Provided session is not a HASH reference", 'error' ); + return 0; + } + + # Get session_id + my $session_id = $session->{_session_id}; + + # Delete session + eval { tied(%$session)->delete() }; + + if ($@) { + $self->lmLog( "Unable to delete CAS session $session_id: $@", 'error' ); + return 0; + } + + $self->lmLog( "CAS session $session_id deleted", 'debug' ); + + return 1; +} + 1; __END__ @@ -142,6 +209,18 @@ Return success for CAS VALIDATE request Find and delete CAS sessions bounded to a primary session +=head2 returnCasServiceValidateError + +Return an error for CAS SERVICE VALIDATE request + +=head2 returnCasServiceValidateSuccess + +Return success for CAS SERVICE VALIDATE request + +=head2 deleteCasSession + +Delete an opened CAS session + =head1 SEE ALSO L