Commit f4514c41 authored by Clément OUDOT's avatar Clément OUDOT
Browse files

Manage all proxy workflow for CAS (#101)

parent b4f5adde
......@@ -4,11 +4,12 @@ use CGI;
use AuthCAS;
# Configuration
my $cas_url = 'https://auth.example.com/cas';
my $cas = new AuthCAS( casUrl => $cas_url );
my $cgi = new CGI;
my $pgtUrl = $cgi->url() . "%3Fproxy%3D1";
my $pgtFile = '/tmp/pgt.txt';
my $cas_url = 'https://auth.example.com/cas';
my $cas = new AuthCAS( casUrl => $cas_url );
my $cgi = new CGI;
my $pgtUrl = $cgi->url() . "%3Fproxy%3D1";
my $pgtFile = '/tmp/pgt.txt';
my $proxiedService = 'http://webmail';
# Act as a CAS proxy
$cas->proxyMode( pgtFile => '/tmp/pgt.txt', pgtCallbackUrl => $pgtUrl );
......@@ -41,7 +42,7 @@ else {
# Ticket receveived
else {
print $cgi->h1("CAS login done");
print $cgi->h2("Received ticket: $ticket");
print $cgi->h2("Service ticket: $ticket");
# Get user
my $user = $cas->validateST( $cgi->url(), $ticket );
......@@ -56,17 +57,37 @@ else {
my $pgtId = $cas->{pgtId};
if ($pgtId) {
print $cgi->h2("Proxy granting ticket: $pgtId");
# Try to request proxy ticket
my $pt = $cas->retrievePT($proxiedService);
if ($pt) {
print $cgi->h2("Proxy ticket: $pt");
# Use proxy ticket
my ( $puser, @proxies ) =
$cas->validatePT( $proxiedService, $pt );
print $cgi->h2("Proxied user: $puser");
print $cgi->h2("Proxies used: @proxies");
}
else {
print $cgi->h2( "Error: " . &AuthCAS::get_errors() );
}
}
else {
print $cgi->h2("Error: Unable to get proxy granting ticket");
}
}
print $cgi->end_html();
}
# Remove PGT file
unlink $pgtFile;
# Remove PGT file
unlink $pgtFile;
}
exit;
......@@ -176,9 +176,14 @@ sub issuerForUnAuthUser {
}
# 4. SERVICE VALIDATE [CAS 2.0]
if ( $url =~ /\Q$cas_serviceValidate_url\E/io ) {
# 5. PROXY VALIDATE [CAS 2.0]
if ( $url =~ /(\Q$cas_serviceValidate_url\E|\Q$cas_proxyValidate_url\E)/io )
{
$self->lmLog( "URL $url detected as an CAS SERVICE VALIDATE URL",
my $urlType =
( $url =~ /\Q$cas_serviceValidate_url\E/ ? 'SERVICE' : 'PROXY' );
$self->lmLog( "URL $url detected as an CAS $urlType VALIDATE URL",
'debug' );
# GET parameters
......@@ -198,27 +203,37 @@ sub issuerForUnAuthUser {
}
$self->lmLog(
"Get service validate request with ticket $ticket for service $service",
"Get "
. lc($urlType)
. " validate request with ticket $ticket for service $service",
'debug'
);
# Get CAS session corresponding to ticket
unless ( $ticket =~ s/^ST-// ) {
if ( $urlType eq 'SERVICE' and !( $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' );
}
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' );
}
my $casServiceSession = $self->getCasSession($ticket);
unless ($casServiceSession) {
$self->lmLog( "Service ticket session $ticket not found", 'error' );
$self->lmLog( "$urlType ticket session $ticket not found",
'error' );
$self->returnCasServiceValidateError( 'INVALID_TICKET',
'Ticket not found' );
}
$self->lmLog( "Service ticket session $ticket found", 'debug' );
$self->lmLog( "$urlType ticket session $ticket found", 'debug' );
# Check service
unless ( $service eq $casServiceSession->{service} ) {
......@@ -246,6 +261,9 @@ sub issuerForUnAuthUser {
$self->lmLog( "Renew parameter not managed", 'warn' );
}
# Proxies (for PROXY VALIDATE only)
my $proxies = $casServiceSession->{proxies};
# Proxy granting ticket
if ($pgtUrl) {
......@@ -258,6 +276,7 @@ sub issuerForUnAuthUser {
if ($casProxyGrantingSession) {
# PGT session
$casProxyGrantingSession->{type} = 'casProxyGranting';
$casProxyGrantingSession->{service} = $service;
$casProxyGrantingSession->{_cas_id} =
......@@ -265,10 +284,16 @@ sub issuerForUnAuthUser {
$casProxyGrantingSession->{_utime} =
$casServiceSession->{_utime};
# Trace proxies
$casProxyGrantingSession->{proxies} =
( $proxies
? $proxies . $self->{multiValuesSeparator} . $pgtUrl
: $pgtUrl );
my $casProxyGrantingSessionID =
$casProxyGrantingSession->{_session_id};
my $casProxyGrantingTicket =
"TGT-" . $casProxyGrantingSessionID;
"PGT-" . $casProxyGrantingSessionID;
untie %$casProxyGrantingSession;
......@@ -344,7 +369,81 @@ sub issuerForUnAuthUser {
# Return success message
$self->returnCasServiceValidateSuccess( $username,
$casProxyGrantingTicketIOU );
$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);
# We should not be there
return PE_ERROR;
......@@ -496,6 +595,32 @@ sub issuerForAuthUser {
return PE_OK;
}
# 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;
}
return PE_OK;
}
......
......@@ -89,13 +89,14 @@ sub returnCasServiceValidateError {
$self->quit();
}
## @method void returnCasServiceValidateSuccess(string username, string pgtIou)
## @method void returnCasServiceValidateSuccess(string username, string pgtIou, string proxies)
# Return success for CAS SERVICE VALIDATE request
# @param username User name
# @param pgtIou Proxy granting ticket IOU
# @param proxies List of used CAS proxies
# @return nothing
sub returnCasServiceValidateSuccess {
my ( $self, $username, $pgtIou ) = splice @_;
my ( $self, $username, $pgtIou, $proxies ) = splice @_;
$self->lmLog( "Return CAS service validate success with username $username",
'debug' );
......@@ -110,12 +111,60 @@ sub returnCasServiceValidateSuccess {
print
"\t\t<cas:proxyGrantingTicket>$pgtIou</cas:proxyGrantingTicket>\n";
}
if ($proxies) {
$self->lmLog( "Add proxies $proxies in response", 'debug' );
print "\t\t<cas:proxies>\n";
print "\t\t\t<cas:proxy>$_</cas:proxy>\n"
foreach ( split( /$self->{multiValuesSeparator}/, $proxies ) );
print "\t\t</cas:proxies>\n";
}
print "\t</cas:authenticationSuccess>\n";
print "</cas:serviceResponse>\n";
$self->quit();
}
## @method void returnCasProxyError(string code, string text)
# Return an error for CAS PROXY request
# @param code CAS error code
# @param text Error text
# @return nothing
sub returnCasProxyError {
my ( $self, $code, $text ) = splice @_;
$code ||= 'INTERNAL_ERROR';
$text ||= 'No description provided';
$self->lmLog( "Return CAS proxy error $code ($text)", 'debug' );
print $self->header( -type => 'application/xml' );
print "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n";
print "\t<cas:proxyFailure code=\"$code\">\n";
print "\t\t$text\n";
print "\t</cas:proxyFailure>\n";
print "</cas:serviceResponse>\n";
$self->quit();
}
## @method void returnCasProxySuccess(string ticket)
# Return success for CAS PROXY request
# @param ticket Proxy ticket
# @return nothing
sub returnCasProxySuccess {
my ( $self, $ticket ) = splice @_;
$self->lmLog( "Return CAS proxy success with ticket $ticket", 'debug' );
print $self->header( -type => 'application/xml' );
print "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n";
print "\t<cas:proxySuccess>\n";
print "\t\t<cas:proxyTicket>$ticket</cas:proxyTicket>\n";
print "\t</cas:proxySuccess>\n";
print "</cas:serviceResponse>\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
......@@ -254,6 +303,14 @@ Return an error for CAS SERVICE VALIDATE request
Return success for CAS SERVICE VALIDATE request
=head2 returnCasProxyError
Return an error for CAS PROXY request
=head2 returnCasProxySuccess
Return success for CAS PROXY request
=head2 deleteCasSession
Delete an opened CAS session
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment