SAML: first work on dispatching logout requests to SP during IDP SLO process

This commit is contained in:
Thomas CHEMINEAU 2010-04-22 17:01:37 +00:00
parent c387e47e4f
commit cd8b59998b
2 changed files with 164 additions and 33 deletions

View File

@ -6,6 +6,7 @@
package Lemonldap::NG::Portal::IssuerDBSAML;
use strict;
use Lemonldap::NG::Common::Conf::SAML::Metadata;
use Lemonldap::NG::Portal::Simple;
use Lemonldap::NG::Portal::_SAML;
our @ISA = qw(Lemonldap::NG::Portal::_SAML);
@ -671,39 +672,7 @@ sub issuerForAuthUser {
$self->lmLog( "SLO: Logout request is valid", 'debug' );
# Get EntityID
my $entityID = $logout->request->Issuer->content;
$self->lmLog( "Request issued from $entityID", 'debug' );
# TODO
# Get all entityID into the current session, to send logout
# requests on all of them.
my @entitiesID = $session =~ /RemoteProviderID="[^"]+"/g;
@entitiesID = map {
my $id = $_;
$id =~ s/RemoteProviderID="([^"]+)"/$1/;
$id;
} @entitiesID;
# Foreach SP found in session, get it from configuration,
# and send the appropriate logout request (HTTP,POST,SOAP).
foreach (@entitiesID) {
# Do not process logout on SP that initiate the
# logout request
next if ($entityID =~ /^$_$/);
# Find EntityID in SPList
unless ( defined $self->{_spList}->{$entityID} ) {
$self->lmLog(
"$entityID does not match any known SP", 'error' );
return PE_ERROR;
}
$self->lmLog( "Initiate logout request on $_", 'debug' );
}
$self->sendLogoutRequestToServiceProviders($logout);
# Validate request if no previous error
unless ( $self->validateLogoutRequest($logout) ) {
@ -831,6 +800,137 @@ sub sendLogoutResponseAfterLogoutRequest {
return 1;
}
sub sendLogoutRequestToServiceProviders {
my $self = shift;
my $logout = shift;
my $server = $self->{_lassoServer};
# Get EntityID
my $entityID = $logout->request->Issuer->content;
# Reset providerID into Lasso::Logout object
$self->resetProviderIdIndex($logout);
# Page header
print $self->header();
print $self->start_html();
print '<ul>';
# Foreach SP found in session, get it from configuration, and send the
# appropriate logout request (HTTP,POST,SOAP).
while ( my $providerID = $self->getNextProviderId($logout) ) {
# Do not process logout on SP that initiate the logout request
next if ($entityID =~ /^$providerID$/);
# Find EntityID in SPList
unless ( defined $self->{_spList}->{$providerID} ) {
$self->lmLog( "$entityID does not match any known SP", 'error' );
return PE_ERROR;
}
# Get first HTTP method
my $protocolType = Lasso::Constants::MD_PROTOCOL_TYPE_SINGLE_LOGOUT;
my $method =
$self->getFirstHttpMethod( $server, $providerID, $protocolType );
# Initiate the logout request
unless ( $self->initLogoutRequest( $logout, $providerID, $method ) )
{
$self->lmLog( "Initiate logout request failed for $providerID",
'error' );
next;
}
# Build request message
unless ( $self->buildLogoutRequestMsg( $logout ) )
{
$self->lmLog( "Build logout request failed for $providerID",
'error' );
next;
}
# Send logout request to the provider depending of the request method
# HTTP-REDIRECT
if ( $method == Lasso::Constants::HTTP_METHOD_REDIRECT ) {
# Redirect user to response URL
my $slo_url = $logout->msg_url;
print '<li>' . $providerID . '...'
. '<iframe src="' . $slo_url . '" alt="" marginwidth="0"'
. 'marginheight="0" scrolling="no" style="border: none"'
. ' width="12" height="12">'
. '<img src="' . $slo_url . '" width="12" height="12"></img>'
. '</iframe></li>';
}
# HTTP-POST
if ( $method == Lasso::Constants::HTTP_METHOD_POST ) {
# Use autosubmit form
my $slo_url = $logout->msg_url;
my $slo_body = $logout->msg_body;
#$self->{postUrl} = $slo_url;
#$self->{postFields} = { 'SAMLResponse' => $slo_body };
# RelayState
#$self->{postFields}->{'RelayState'} = $relaystate
#if ($relaystate);
$self->lmLog( "POST method not yet available", 'debug' );
}
# HTTP-SOAP
if ( $method == Lasso::Constants::HTTP_METHOD_SOAP ) {
my $slo_url = $logout->msg_url;
my $slo_body = $logout->msg_body;
# Send SOAP request and manage response
my $sp_response = $self->sendSOAPMessage( $slo_url, $slo_body );
unless ($sp_response) {
$self->lmLog( "No logout response to SOAP request", 'error' );
next;
}
# Create Logout object
my $sp_logout = $self->createLogout($server);
# Process logout response
my $sp_result =
$self->processLogoutResponseMsg( $sp_logout, $sp_response );
unless ($sp_result) {
$self->lmLog( "Fail to process logout response", 'error' );
next;
}
$self->lmLog( "Logout response is valid", 'debug' );
# Replay protection
my $samlID = $sp_logout->response()->InResponseTo;
unless ( $self->replayProtection($samlID) ) {
# Logout request was already consumed or is expired
$self->lmLog( "Message $samlID already used or expired", 'error' );
next;
}
}
}
# End page
print '</ul>';
print $self->end_html();
}
1;
__END__

View File

@ -577,6 +577,37 @@ sub getOrganizationName {
return $data->{OrganizationName}->{content};
}
## @method string getNextProviderId(Lasso::Logout logout)
# Returns the provider id from providerID_index in list of providerIDs in
# principal session with the exception of initial service provider ID.
# @param logout Lasso::Logout object
# @return string
sub getNextProviderId {
my $self = shift;
my $logout = shift;
my $providerId;
eval { $providerId = Lasso::Logout::get_next_providerID($logout); };
if ($@) {
$self->checkLassoError($@);
return;
}
return $providerId;
}
## @method boolean resetProviderIdIndex(Lasso::Logout logout)
# Reset the providerID_index attribute in Lasso::Logout object
# @param logout Lasso::Logout object
# @return boolean
sub resetProviderIdIndex {
my $self = shift;
my $logout = shift;
eval { Lasso::Logout::reset_providerID_index($logout); };
return $self->checkLassoError($@);
}
## @method Lasso::Login createAuthnRequest(Lasso::Server server, string idp, int method, boolean forceAuthn, boolean isPassive, string nameIDFormat, boolean allowProxiedAuthn, boolean signSSOMessage, string requestedAuthnContext)
# Create authentication request for selected IDP
# @param server Lasso::Server object