2009-04-07 22:38:24 +02:00
|
|
|
## @file
|
2009-12-10 18:03:57 +01:00
|
|
|
# SAML Issuer file
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
## @class
|
2009-12-10 18:03:57 +01:00
|
|
|
# SAML Issuer class
|
|
|
|
package Lemonldap::NG::Portal::IssuerDBSAML;
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
use strict;
|
2010-04-22 19:01:37 +02:00
|
|
|
use Lemonldap::NG::Common::Conf::SAML::Metadata;
|
2009-04-07 22:38:24 +02:00
|
|
|
use Lemonldap::NG::Portal::Simple;
|
2010-02-26 11:53:43 +01:00
|
|
|
use Lemonldap::NG::Portal::_SAML;
|
|
|
|
our @ISA = qw(Lemonldap::NG::Portal::_SAML);
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
our $VERSION = '0.01';
|
|
|
|
|
2009-12-10 18:03:57 +01:00
|
|
|
## @method void issuerDBInit()
|
|
|
|
# Load and check SAML configuration
|
|
|
|
# @return Lemonldap::NG::Portal error code
|
|
|
|
sub issuerDBInit {
|
2009-04-07 22:38:24 +02:00
|
|
|
my $self = shift;
|
2010-03-25 12:24:52 +01:00
|
|
|
|
|
|
|
# Load SAML service
|
|
|
|
return PE_ERROR unless $self->loadService();
|
|
|
|
|
|
|
|
# Load SAML identity providers
|
|
|
|
return PE_ERROR unless $self->loadSPs();
|
|
|
|
|
|
|
|
PE_OK;
|
2009-04-07 22:38:24 +02:00
|
|
|
}
|
|
|
|
|
2009-12-10 18:03:57 +01:00
|
|
|
## @apmethod int issuerForUnAuthUser()
|
2010-04-07 14:27:50 +02:00
|
|
|
# Check if there is an SAML authentication request
|
|
|
|
# Called only for unauthenticated users, check isPassive flag
|
2009-04-07 22:38:24 +02:00
|
|
|
# @return Lemonldap::NG::Portal error code
|
2009-12-10 18:03:57 +01:00
|
|
|
sub issuerForUnAuthUser {
|
2010-03-26 17:47:17 +01:00
|
|
|
my $self = shift;
|
2010-03-26 14:56:37 +01:00
|
|
|
my $server = $self->{_lassoServer};
|
|
|
|
|
2010-03-26 17:02:27 +01:00
|
|
|
# Get configuration parameter
|
2010-03-26 14:56:37 +01:00
|
|
|
my $saml_sso_soap_url =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceSOAP", 1 );
|
|
|
|
my $saml_sso_soap_url_ret =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceSOAP", 2 );
|
|
|
|
my $saml_sso_get_url =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceHTTP", 1 );
|
|
|
|
my $saml_sso_get_url_ret =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceHTTP", 2 );
|
2010-04-20 12:04:34 +02:00
|
|
|
my $saml_slo_soap_url =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceSOAP", 1 );
|
|
|
|
my $saml_slo_soap_url_ret =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceSOAP", 2 );
|
|
|
|
my $saml_slo_get_url =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceHTTP", 1 );
|
|
|
|
my $saml_slo_get_url_ret =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceHTTP", 2 );
|
2010-04-08 13:03:53 +02:00
|
|
|
my $saml_ars_url = $self->getMetaDataURL(
|
|
|
|
"samlIDPSSODescriptorArtifactResolutionServiceArtifact");
|
2010-03-26 14:56:37 +01:00
|
|
|
|
2010-03-26 17:47:17 +01:00
|
|
|
# Get HTTP request informations to know
|
|
|
|
# if we are receving SAML request or response
|
|
|
|
my $url = $self->url();
|
|
|
|
my $request_method = $self->request_method();
|
|
|
|
my $content_type = $self->content_type();
|
2010-03-26 14:56:37 +01:00
|
|
|
|
2010-04-20 12:04:34 +02:00
|
|
|
# 1.1. SSO
|
2010-04-08 12:16:13 +02:00
|
|
|
if ( $url =~ /^(\Q$saml_sso_soap_url\E|\Q$saml_sso_get_url\E)$/i ) {
|
2010-03-26 14:56:37 +01:00
|
|
|
|
2010-03-26 17:47:17 +01:00
|
|
|
$self->lmLog( "URL $url detected as an SSO request URL", 'debug' );
|
2010-03-26 14:56:37 +01:00
|
|
|
|
2010-03-26 17:02:27 +01:00
|
|
|
# Check message
|
|
|
|
my ( $request, $response, $method, $relaystate, $artifact ) =
|
2010-03-26 17:47:17 +01:00
|
|
|
$self->checkMessage( $url, $request_method, $content_type );
|
2010-03-26 14:56:37 +01:00
|
|
|
|
2010-03-26 17:02:27 +01:00
|
|
|
# Process the request
|
2010-03-26 17:47:17 +01:00
|
|
|
if ($request) {
|
2010-03-26 14:56:37 +01:00
|
|
|
|
2010-03-26 17:02:27 +01:00
|
|
|
# Create Login object
|
2010-03-26 17:47:17 +01:00
|
|
|
my $login = $self->createLogin($server);
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-03-26 14:56:37 +01:00
|
|
|
# Process authentication request
|
|
|
|
my $result;
|
|
|
|
if ($artifact) {
|
|
|
|
$result = $self->processArtRequestMsg( $login, $request );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$result = $self->processAuthnRequestMsg( $login, $request );
|
|
|
|
}
|
|
|
|
|
|
|
|
unless ($result) {
|
|
|
|
$self->lmLog( "SSO: Fail to process authentication request",
|
|
|
|
'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "SSO: authentication request is valid", 'debug' );
|
|
|
|
|
|
|
|
# Get SAML request
|
|
|
|
my $saml_request = $login->request();
|
|
|
|
unless ($saml_request) {
|
|
|
|
$self->lmLog( "No SAML request found", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Check isPassive flag
|
|
|
|
my $isPassive = $saml_request->IsPassive();
|
|
|
|
|
|
|
|
if ($isPassive) {
|
2010-04-07 12:11:21 +02:00
|
|
|
$self->lmLog(
|
|
|
|
"Found isPassive flag in SAML request, not compatible with unauthenticated user",
|
|
|
|
'error'
|
|
|
|
);
|
2010-03-26 14:56:37 +01:00
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-20 12:04:34 +02:00
|
|
|
# 1.2. SLO
|
|
|
|
if ( $url =~
|
|
|
|
/^(\Q$saml_slo_soap_url\E|\Q$saml_slo_soap_url_ret\E|\Q$saml_slo_get_url\E|\Q$saml_slo_get_url_ret\E)$/i
|
|
|
|
)
|
|
|
|
{
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an SLO URL", 'debug' );
|
|
|
|
|
|
|
|
# Create Logout object
|
|
|
|
my $logout = $self->createLogout($server);
|
|
|
|
|
|
|
|
# Check SAML Message
|
|
|
|
my ( $request, $response, $method, $relaystate, $artifact ) =
|
|
|
|
$self->checkMessage( $url, $request_method, $content_type, "logout" );
|
|
|
|
|
|
|
|
if ($request) {
|
|
|
|
|
|
|
|
# Process logout request
|
|
|
|
unless ( $self->processLogoutRequestMsg( $logout, $request ) ) {
|
|
|
|
$self->lmLog( "SLO: Fail to process logout request", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "SLO: Logout request is valid", 'debug' );
|
|
|
|
|
|
|
|
# Get SAML request
|
|
|
|
my $saml_request = $logout->request();
|
|
|
|
unless ($saml_request) {
|
|
|
|
$self->lmLog( "No SAML request found", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set RelayState
|
|
|
|
if ($relaystate) {
|
|
|
|
$logout->msg_relayState($relaystate);
|
|
|
|
$self->lmLog( "Set $relaystate in RelayState", 'debug' );
|
|
|
|
}
|
|
|
|
|
|
|
|
# Logout response
|
|
|
|
unless ( $self->buildLogoutResponseMsg($logout) ) {
|
|
|
|
$self->lmLog( "Unable to build SLO response", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-04-20 17:31:21 +02:00
|
|
|
# Send logout response
|
|
|
|
return PE_ERROR
|
2010-04-26 12:02:26 +02:00
|
|
|
unless (
|
|
|
|
$self->sendLogoutResponseAfterLogoutRequest(
|
|
|
|
$logout, $method, $relaystate, 0
|
|
|
|
)
|
|
|
|
);
|
2010-04-20 12:04:34 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# 1.3. Artifacts
|
2010-04-08 13:03:53 +02:00
|
|
|
if ( $url =~ /^(\Q$saml_ars_url\E)$/i ) {
|
|
|
|
|
2010-04-12 11:09:53 +02:00
|
|
|
$self->lmLog( "URL $url detected as an artifact resolution service URL",
|
2010-04-08 13:03:53 +02:00
|
|
|
'debug' );
|
|
|
|
|
2010-04-12 11:09:53 +02:00
|
|
|
# Artifact request are sent with SOAP trough POST
|
|
|
|
my $art_request = $self->param('POSTDATA');
|
|
|
|
my $art_response;
|
|
|
|
|
2010-04-08 18:28:10 +02:00
|
|
|
# Create Login object
|
|
|
|
my $login = $self->createLogin($server);
|
|
|
|
|
2010-04-12 11:09:53 +02:00
|
|
|
# Create artifact response
|
|
|
|
unless ( $art_response =
|
|
|
|
$self->createArtifactResponse( $login, $art_request ) )
|
|
|
|
{
|
|
|
|
$self->lmLog( "Unable to create artifact response message",
|
2010-04-08 18:28:10 +02:00
|
|
|
'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-04-12 11:09:53 +02:00
|
|
|
$self->{SOAPMessage} = $art_response;
|
2010-04-09 18:42:50 +02:00
|
|
|
|
|
|
|
$self->lmLog( "Send SOAP Message: " . $self->{SOAPMessage}, 'debug' );
|
2010-04-08 18:28:10 +02:00
|
|
|
|
|
|
|
# Return SOAP message
|
|
|
|
$self->returnSOAPMessage();
|
|
|
|
|
2010-04-12 10:26:18 +02:00
|
|
|
# If we are here, there was a problem with SOAP request
|
|
|
|
$self->lmLog( "Artifact response was not sent trough SOAP", 'error' );
|
|
|
|
return PE_ERROR;
|
2010-04-12 11:09:53 +02:00
|
|
|
|
2010-04-08 13:03:53 +02:00
|
|
|
}
|
|
|
|
|
2009-04-07 22:38:24 +02:00
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2009-12-10 18:03:57 +01:00
|
|
|
## @apmethod int issuerForAuthUser()
|
2009-04-07 22:38:24 +02:00
|
|
|
# Check if there is an SAML authentication request for an authenticated user
|
2010-04-07 14:27:50 +02:00
|
|
|
# Build assertions and redirect user
|
2009-04-07 22:38:24 +02:00
|
|
|
# @return Lemonldap::NG::Portal error code
|
2009-12-10 18:03:57 +01:00
|
|
|
sub issuerForAuthUser {
|
2010-04-14 17:37:57 +02:00
|
|
|
my $self = shift;
|
2010-04-02 18:19:10 +02:00
|
|
|
my $server = $self->{_lassoServer};
|
2010-04-07 14:27:50 +02:00
|
|
|
my $login;
|
2010-04-07 17:14:17 +02:00
|
|
|
my $protocolProfile;
|
|
|
|
my $artifact_method;
|
2010-04-07 18:37:23 +02:00
|
|
|
my $authn_context;
|
2010-04-02 18:19:10 +02:00
|
|
|
|
2010-04-12 17:42:38 +02:00
|
|
|
# Session ID
|
|
|
|
my $session_id = $self->{sessionInfo}->{_session_id} || $self->{id};
|
|
|
|
|
2010-04-02 18:19:10 +02:00
|
|
|
# Get configuration parameter
|
|
|
|
my $saml_sso_soap_url =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceSOAP", 1 );
|
|
|
|
my $saml_sso_soap_url_ret =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceSOAP", 2 );
|
|
|
|
my $saml_sso_get_url =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceHTTP", 1 );
|
|
|
|
my $saml_sso_get_url_ret =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleSignOnServiceHTTP", 2 );
|
2010-04-20 12:04:34 +02:00
|
|
|
my $saml_slo_soap_url =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceSOAP", 1 );
|
|
|
|
my $saml_slo_soap_url_ret =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceSOAP", 2 );
|
|
|
|
my $saml_slo_get_url =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceHTTP", 1 );
|
|
|
|
my $saml_slo_get_url_ret =
|
|
|
|
$self->getMetaDataURL( "samlIDPSSODescriptorSingleLogoutServiceHTTP", 2 );
|
2010-04-02 18:19:10 +02:00
|
|
|
|
|
|
|
# Get HTTP request informations to know
|
|
|
|
# if we are receving SAML request or response
|
|
|
|
my $url = $self->url();
|
|
|
|
my $request_method = $self->request_method();
|
|
|
|
my $content_type = $self->content_type();
|
|
|
|
|
2010-04-20 12:04:34 +02:00
|
|
|
# 1.1. SSO
|
2010-04-08 12:16:13 +02:00
|
|
|
if ( $url =~ /^(\Q$saml_sso_soap_url\E|\Q$saml_sso_get_url\E)$/i ) {
|
2010-04-02 18:19:10 +02:00
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an SSO request URL", 'debug' );
|
|
|
|
|
|
|
|
# Check message
|
|
|
|
my ( $request, $response, $method, $relaystate, $artifact ) =
|
|
|
|
$self->checkMessage( $url, $request_method, $content_type );
|
2010-03-26 14:56:37 +01:00
|
|
|
|
2010-04-02 18:19:10 +02:00
|
|
|
# Process the request
|
2010-04-07 12:11:21 +02:00
|
|
|
if ($request) {
|
2010-04-02 18:19:10 +02:00
|
|
|
|
|
|
|
# Create Login object
|
2010-04-07 14:27:50 +02:00
|
|
|
$login = $self->createLogin($server);
|
2010-04-02 18:19:10 +02:00
|
|
|
|
2010-04-12 15:23:22 +02:00
|
|
|
# Load Session and Identity if they exist
|
|
|
|
my $session = $self->{sessionInfo}->{_lassoSessionDump};
|
|
|
|
my $identity = $self->{sessionInfo}->{_lassoIdentityDump};
|
|
|
|
|
|
|
|
if ($session) {
|
|
|
|
unless ( $self->setSessionFromDump( $login, $session ) ) {
|
|
|
|
$self->lmLog( "Unable to load Lasso Session", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
$self->lmLog( "Lasso Session loaded", 'debug' );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($identity) {
|
|
|
|
unless ( $self->setIdentityFromDump( $login, $identity ) ) {
|
|
|
|
$self->lmLog( "Unable to load Lasso Identity", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
$self->lmLog( "Lasso Identity loaded", 'debug' );
|
|
|
|
}
|
|
|
|
|
2010-04-02 18:19:10 +02:00
|
|
|
# Process authentication request
|
|
|
|
my $result;
|
|
|
|
if ($artifact) {
|
|
|
|
$result = $self->processArtRequestMsg( $login, $request );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$result = $self->processAuthnRequestMsg( $login, $request );
|
|
|
|
}
|
|
|
|
|
|
|
|
unless ($result) {
|
|
|
|
$self->lmLog( "SSO: Fail to process authentication request",
|
|
|
|
'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-04-15 16:42:17 +02:00
|
|
|
# Get EntityID
|
|
|
|
my $entityID = $login->request->Issuer->content;
|
|
|
|
|
|
|
|
$self->lmLog( "Request issued from $entityID", 'debug' );
|
|
|
|
|
|
|
|
# Find EntityID in SPList
|
|
|
|
unless ( defined $self->{_spList}->{$entityID} ) {
|
|
|
|
$self->lmLog( "$entityID do not match any known SP", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-04-15 17:40:07 +02:00
|
|
|
# Get SP Name from EntityID
|
|
|
|
my $sp = $self->{_spList}->{$entityID}->{name};
|
|
|
|
|
|
|
|
$self->lmLog( "Using SP $sp configuration", 'debug' );
|
2010-04-15 16:42:17 +02:00
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
# Validate request
|
|
|
|
unless ( $self->validateRequestMsg( $login, 1, 1 ) ) {
|
|
|
|
$self->lmLog( "Unable to validate SSO request message",
|
|
|
|
'error' );
|
|
|
|
return PE_ERROR;
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-04-07 14:27:50 +02:00
|
|
|
|
2010-04-02 18:19:10 +02:00
|
|
|
$self->lmLog( "SSO: authentication request is valid", 'debug' );
|
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# TODO Check AuthnRequest conditions
|
|
|
|
|
2010-04-14 18:22:55 +02:00
|
|
|
# Map authenticationLevel with SAML2 authentication context
|
2010-04-15 11:06:53 +02:00
|
|
|
my $authenticationLevel =
|
|
|
|
$self->{sessionInfo}->{authenticationLevel};
|
2010-04-07 18:37:23 +02:00
|
|
|
|
2010-04-14 18:22:55 +02:00
|
|
|
$authn_context = $self->getAuthnContext("unspecified");
|
2010-04-15 11:06:53 +02:00
|
|
|
$authn_context = $self->getAuthnContext("password")
|
|
|
|
if ( $authenticationLevel == "2" );
|
|
|
|
$authn_context =
|
|
|
|
$self->getAuthnContext("password-protected-transport")
|
|
|
|
if ( $authenticationLevel == "3" );
|
|
|
|
$authn_context = $self->getAuthnContext("tls-client")
|
|
|
|
if ( $authenticationLevel == "5" );
|
2010-04-07 18:37:23 +02:00
|
|
|
|
|
|
|
$self->lmLog( "Authentication context is $authn_context", 'debug' );
|
|
|
|
|
|
|
|
# Build Assertion
|
|
|
|
unless ( $self->buildAssertion( $login, $authn_context ) ) {
|
|
|
|
$self->lmLog( "Unable to build assertion", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "SSO: assertion is built", 'debug' );
|
2010-04-07 14:27:50 +02:00
|
|
|
|
2010-04-14 13:14:24 +02:00
|
|
|
# Build NameID
|
|
|
|
# Default NameID Format
|
|
|
|
my $nameIDFormat = $self->getNameIDFormat("email");
|
|
|
|
my $nameIDContent;
|
|
|
|
|
|
|
|
# Check NameID Policy in request
|
|
|
|
if ( $login->request()->NameIDPolicy ) {
|
|
|
|
$nameIDFormat = $login->request()->NameIDPolicy->Format();
|
|
|
|
}
|
|
|
|
|
|
|
|
# TODO use options to map format with session vars
|
|
|
|
# TODO Take the first value of a multivaluated var ( split ;)
|
|
|
|
# TODO support other formats
|
|
|
|
$nameIDContent = $self->{sessionInfo}->{mail}
|
|
|
|
if ( $nameIDFormat eq $self->getNameIDFormat("email") );
|
|
|
|
|
2010-04-26 16:30:54 +02:00
|
|
|
if ( $login->nameIdentifier ) {
|
|
|
|
$login->nameIdentifier->Format($nameIDFormat);
|
|
|
|
$login->nameIdentifier->content($nameIDContent)
|
|
|
|
if $nameIDContent;
|
|
|
|
}
|
|
|
|
else {
|
2010-04-26 12:02:26 +02:00
|
|
|
my $nameIdentifier = Lasso::Saml2NameID->new();
|
|
|
|
$nameIdentifier->Format($nameIDFormat);
|
|
|
|
$nameIdentifier->content($nameIDContent) if $nameIDContent;
|
|
|
|
$login->nameIdentifier($nameIdentifier);
|
2010-04-26 16:30:54 +02:00
|
|
|
}
|
2010-04-14 13:14:24 +02:00
|
|
|
|
|
|
|
$self->lmLog( "NameID Format is $nameIDFormat", 'debug' );
|
|
|
|
$self->lmLog( "NameID Content is $nameIDContent", 'debug' );
|
|
|
|
|
2010-04-16 10:55:56 +02:00
|
|
|
# Push mandatory attributes
|
2010-04-15 17:40:07 +02:00
|
|
|
my @attributes;
|
|
|
|
|
|
|
|
foreach (
|
|
|
|
keys %{ $self->{samlSPMetaDataExportedAttributes}->{$sp} } )
|
|
|
|
{
|
|
|
|
|
|
|
|
# Extract fields from exportedAttr value
|
|
|
|
my ( $mandatory, $name, $format, $friendly_name ) =
|
|
|
|
split( /;/,
|
|
|
|
$self->{samlSPMetaDataExportedAttributes}->{$sp}->{$_} );
|
|
|
|
|
|
|
|
# Name is required
|
|
|
|
next unless $name;
|
|
|
|
|
|
|
|
# Do not send attribute if not mandatory
|
|
|
|
unless ($mandatory) {
|
|
|
|
$self->lmLog( "SAML2 attribute $name is not mandatory",
|
|
|
|
'debug' );
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Error if corresponding attribute is not in user session
|
|
|
|
my $value = $self->{sessionInfo}->{$_};
|
|
|
|
unless ( defined $value ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Session key $_ is required to set SAML $name attribute",
|
|
|
|
'error'
|
|
|
|
);
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog(
|
|
|
|
"SAML2 attribute $name will be set with $_ session key",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# SAML2 attribute
|
|
|
|
my $attribute;
|
|
|
|
|
|
|
|
eval { $attribute = Lasso::Saml2Attribute->new(); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Default values
|
|
|
|
$friendly_name ||= $name;
|
|
|
|
$format ||= Lasso::Constants::SAML2_ATTRIBUTE_NAME_FORMAT_BASIC;
|
|
|
|
|
|
|
|
# Set attribute properties
|
|
|
|
$attribute->Name($name);
|
|
|
|
$attribute->NameFormat($format);
|
|
|
|
$attribute->FriendlyName($friendly_name);
|
|
|
|
|
|
|
|
# Set attribute value(s)
|
|
|
|
my @values = split $self->{multiValuesSeparator}, $value;
|
|
|
|
my @saml2values;
|
|
|
|
|
|
|
|
foreach (@values) {
|
|
|
|
|
|
|
|
# SAML2 attribute value
|
|
|
|
my $saml2value;
|
|
|
|
|
|
|
|
eval { $saml2value = Lasso::Saml2AttributeValue->new(); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
my @any;
|
|
|
|
|
|
|
|
my $textNode;
|
|
|
|
eval { $textNode = Lasso::MiscTextNode->new(); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$textNode->text_child(1);
|
|
|
|
$textNode->content($_);
|
|
|
|
|
|
|
|
push @any, $textNode;
|
|
|
|
|
|
|
|
$saml2value->any(@any);
|
|
|
|
|
|
|
|
push @saml2values, $saml2value;
|
|
|
|
|
|
|
|
$self->lmLog( "Push $_ in SAML attribute $name", 'debug' );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
$attribute->AttributeValue(@saml2values);
|
|
|
|
|
2010-04-16 10:55:56 +02:00
|
|
|
# Push attribute in attribute list
|
|
|
|
push @attributes, $attribute;
|
|
|
|
|
2010-04-15 17:40:07 +02:00
|
|
|
}
|
2010-04-07 14:27:50 +02:00
|
|
|
|
2010-04-16 10:55:56 +02:00
|
|
|
# Create attribute statement
|
|
|
|
my $attribute_statement;
|
|
|
|
|
|
|
|
eval {
|
|
|
|
$attribute_statement = Lasso::Saml2AttributeStatement->new();
|
|
|
|
};
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Register attributes in attribute statement
|
|
|
|
$attribute_statement->Attribute(@attributes);
|
|
|
|
|
|
|
|
# Get response assertion
|
|
|
|
my @response_assertions = $login->response->Assertion;
|
|
|
|
|
|
|
|
unless ( $response_assertions[0] ) {
|
|
|
|
$self->lmLog( "Unable to get response assertion", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set subject NameID
|
|
|
|
$response_assertions[0]
|
|
|
|
->set_subject_name_id( $login->nameIdentifier );
|
|
|
|
|
|
|
|
# Add attribute statement in response assertion
|
|
|
|
my @attributes_statement = ($attribute_statement);
|
|
|
|
$response_assertions[0]->AttributeStatement(@attributes_statement);
|
|
|
|
|
|
|
|
# Set response assertion
|
|
|
|
$login->response->Assertion(@response_assertions);
|
|
|
|
|
2010-04-07 17:14:17 +02:00
|
|
|
# Build SAML response
|
|
|
|
$protocolProfile = $login->protocolProfile();
|
|
|
|
|
|
|
|
# Artifact
|
|
|
|
if ( $protocolProfile ==
|
|
|
|
Lasso::Constants::LOGIN_PROTOCOL_PROFILE_BRWS_ART )
|
|
|
|
{
|
|
|
|
|
|
|
|
# Choose method
|
|
|
|
$artifact_method = $self->getHttpMethod("artifact-get")
|
|
|
|
if ( $method == $self->getHttpMethod("redirect") );
|
|
|
|
$artifact_method = $self->getHttpMethod("artifact-post")
|
|
|
|
if ( $method == $self->getHttpMethod("post") );
|
|
|
|
|
|
|
|
# Build artifact message
|
|
|
|
unless ( $self->buildArtifactMsg( $login, $artifact_method ) ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Unable to build SSO artifact response message",
|
|
|
|
'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "SSO: artifact response is built", 'debug' );
|
2010-04-14 17:37:57 +02:00
|
|
|
|
2010-04-08 18:28:10 +02:00
|
|
|
# Get artifact ID and Content, and store them
|
2010-04-12 10:26:18 +02:00
|
|
|
my $artifact_id = $login->get_artifact;
|
|
|
|
my $artifact_message = $login->get_artifact_message;
|
2010-04-07 14:27:50 +02:00
|
|
|
|
2010-04-12 17:03:54 +02:00
|
|
|
$self->storeArtifact( $artifact_id, $artifact_message,
|
2010-04-12 17:42:38 +02:00
|
|
|
$session_id );
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-04-02 18:19:10 +02:00
|
|
|
|
2010-04-07 17:14:17 +02:00
|
|
|
# No artifact
|
|
|
|
else {
|
|
|
|
|
|
|
|
unless ( $self->buildAuthnResponseMsg($login) ) {
|
|
|
|
$self->lmLog( "Unable to build SSO response message",
|
|
|
|
'error' );
|
|
|
|
return PE_ERROR;
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-03-26 14:56:37 +01:00
|
|
|
|
2010-04-07 17:14:17 +02:00
|
|
|
$self->lmLog( "SSO: authentication response is built",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-12 15:23:22 +02:00
|
|
|
# Save Identity and Session
|
|
|
|
if ( $login->is_identity_dirty ) {
|
|
|
|
$self->lmLog( "Save Lasso identity in session", 'debug' );
|
|
|
|
$self->updateSession(
|
2010-04-12 17:42:38 +02:00
|
|
|
{ _lassoIdentityDump => $login->get_identity->dump },
|
|
|
|
$session_id );
|
2010-04-12 15:23:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( $login->is_session_dirty ) {
|
|
|
|
$self->lmLog( "Save Lasso session in session", 'debug' );
|
|
|
|
$self->updateSession(
|
2010-04-12 17:42:38 +02:00
|
|
|
{ _lassoSessionDump => $login->get_session->dump },
|
|
|
|
$session_id );
|
2010-04-12 15:23:22 +02:00
|
|
|
}
|
|
|
|
|
2010-04-07 17:14:17 +02:00
|
|
|
# Send SSO Response
|
|
|
|
|
|
|
|
# HTTP-REDIRECT
|
|
|
|
if ( $protocolProfile eq
|
|
|
|
Lasso::Constants::LOGIN_PROTOCOL_PROFILE_REDIRECT
|
|
|
|
or $artifact_method == $self->getHttpMethod("artifact-get") )
|
|
|
|
{
|
|
|
|
|
|
|
|
# Redirect user to response URL
|
|
|
|
my $sso_url = $login->msg_url;
|
|
|
|
$self->lmLog( "Redirect user to $sso_url", 'debug' );
|
|
|
|
|
|
|
|
$self->{urldc} = $sso_url;
|
|
|
|
|
|
|
|
$self->_subProcess(qw(autoRedirect));
|
|
|
|
|
|
|
|
# If we are here, there was a problem with GET request
|
|
|
|
$self->lmLog( "SSO response was not sent trough GET", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# HTTP-POST
|
|
|
|
if ( $protocolProfile eq
|
|
|
|
Lasso::Constants::LOGIN_PROTOCOL_PROFILE_BRWS_POST
|
|
|
|
or $artifact_method == $self->getHttpMethod("artifact-post") )
|
|
|
|
{
|
|
|
|
|
|
|
|
# Use autosubmit form
|
|
|
|
my $sso_url = $login->msg_url;
|
|
|
|
my $sso_body = $login->msg_body;
|
|
|
|
|
|
|
|
$self->{postUrl} = $sso_url;
|
|
|
|
$self->{postFields} = { 'SAMLResponse' => $sso_body };
|
|
|
|
|
|
|
|
# RelayState
|
|
|
|
$self->{postFields}->{'RelayState'} = $login->msg_relayState
|
|
|
|
if ( $login->msg_relayState );
|
|
|
|
|
|
|
|
$self->_subProcess(qw(autoPost));
|
|
|
|
|
|
|
|
# If we are here, there was a problem with POST request
|
|
|
|
$self->lmLog( "SSO response was not sent trough POST",
|
|
|
|
'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
elsif ($response) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Authentication responses are not managed by this module",
|
|
|
|
'debug' );
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
# No request or response
|
|
|
|
# This should not happen
|
|
|
|
$self->lmLog( "No request or response found", 'debug' );
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-20 17:31:21 +02:00
|
|
|
# 1.2. SLO
|
|
|
|
if ( $url =~
|
|
|
|
/^(\Q$saml_slo_soap_url\E|\Q$saml_slo_soap_url_ret\E|\Q$saml_slo_get_url\E|\Q$saml_slo_get_url_ret\E)$/i
|
|
|
|
)
|
|
|
|
{
|
|
|
|
|
|
|
|
$self->lmLog( "URL $url detected as an SLO URL", 'debug' );
|
|
|
|
|
|
|
|
# Create Logout object
|
|
|
|
my $logout = $self->createLogout($server);
|
|
|
|
|
|
|
|
# Check SAML Message
|
|
|
|
my ( $request, $response, $method, $relaystate, $artifact ) =
|
|
|
|
$self->checkMessage( $url, $request_method, $content_type, "logout" );
|
|
|
|
|
|
|
|
if ($request) {
|
|
|
|
|
2010-04-20 17:49:48 +02:00
|
|
|
my $logout_error = 0;
|
|
|
|
|
2010-04-20 17:31:21 +02:00
|
|
|
# Load Session and Identity if they exist
|
|
|
|
my $session = $self->{sessionInfo}->{_lassoSessionDump};
|
|
|
|
my $identity = $self->{sessionInfo}->{_lassoIdentityDump};
|
|
|
|
|
|
|
|
if ($session) {
|
|
|
|
unless ( $self->setSessionFromDump( $logout, $session ) ) {
|
|
|
|
$self->lmLog( "Unable to load Lasso Session", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
$self->lmLog( "Lasso Session loaded", 'debug' );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($identity) {
|
|
|
|
unless ( $self->setIdentityFromDump( $logout, $identity ) ) {
|
|
|
|
$self->lmLog( "Unable to load Lasso Identity", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
$self->lmLog( "Lasso Identity loaded", 'debug' );
|
|
|
|
}
|
|
|
|
|
|
|
|
# Process logout request
|
|
|
|
unless ( $self->processLogoutRequestMsg( $logout, $request ) ) {
|
|
|
|
$self->lmLog( "SLO: Fail to process logout request", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "SLO: Logout request is valid", 'debug' );
|
|
|
|
|
2010-04-23 17:18:08 +02:00
|
|
|
# Proceed to logout on all others SP
|
|
|
|
my $logout_dump = $logout->dump;
|
2010-04-23 18:26:23 +02:00
|
|
|
my $provider_nb =
|
2010-04-26 17:39:38 +02:00
|
|
|
$self->sendLogoutRequestToServiceProviders($logout);
|
2010-04-23 18:26:23 +02:00
|
|
|
|
|
|
|
# Rebuild Lasso::Logout object. All data have already been checked.
|
2010-04-26 12:02:26 +02:00
|
|
|
$logout = Lasso::Logout::new_from_dump( $server, $logout_dump );
|
2010-04-23 17:18:08 +02:00
|
|
|
$self->setSessionFromDump( $logout, $session );
|
|
|
|
$self->setIdentityFromDump( $logout, $identity );
|
2010-04-20 17:31:21 +02:00
|
|
|
|
|
|
|
# Validate request if no previous error
|
2010-04-21 18:54:05 +02:00
|
|
|
unless ( $self->validateLogoutRequest($logout) ) {
|
2010-04-20 17:31:21 +02:00
|
|
|
$self->lmLog( "SLO request is not valid", 'error' );
|
2010-04-22 15:00:32 +02:00
|
|
|
$logout_error = 1;
|
2010-04-20 17:31:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Set RelayState
|
|
|
|
if ($relaystate) {
|
|
|
|
$logout->msg_relayState($relaystate);
|
|
|
|
$self->lmLog( "Set $relaystate in RelayState", 'debug' );
|
|
|
|
}
|
|
|
|
|
|
|
|
# Logout response
|
|
|
|
unless ( $self->buildLogoutResponseMsg($logout) ) {
|
|
|
|
$self->lmLog( "Unable to build SLO response", 'error' );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-04-21 18:54:05 +02:00
|
|
|
# Delete Session
|
2010-04-26 12:02:26 +02:00
|
|
|
if ( !$logout_error ) {
|
2010-04-21 18:54:05 +02:00
|
|
|
my $user = $self->{sessionInfo}->{user};
|
2010-04-26 12:02:26 +02:00
|
|
|
my $local_session = $self->getApacheSession( $session_id, 1 );
|
2010-04-22 15:00:32 +02:00
|
|
|
unless ( $self->_deleteSession($local_session) ) {
|
2010-04-26 12:02:26 +02:00
|
|
|
$self->lmLog(
|
|
|
|
"Fail to delete session $session_id for user $user",
|
2010-04-21 18:54:05 +02:00
|
|
|
'debug' );
|
|
|
|
}
|
2010-04-22 15:00:32 +02:00
|
|
|
}
|
2010-04-21 18:54:05 +02:00
|
|
|
|
2010-04-20 17:31:21 +02:00
|
|
|
# Send logout response
|
2010-04-23 18:26:23 +02:00
|
|
|
# The process could be stopped here, if no information have to be
|
|
|
|
# displayed to the user.
|
2010-04-26 12:02:26 +02:00
|
|
|
my $err =
|
|
|
|
$self->sendLogoutResponseAfterLogoutRequest( $logout, $method,
|
|
|
|
$relaystate, $provider_nb );
|
|
|
|
if ( $err eq PE_INFO ) {
|
2010-04-23 18:26:23 +02:00
|
|
|
return PE_INFO;
|
|
|
|
}
|
2010-04-26 12:02:26 +02:00
|
|
|
elsif ( !$err ) {
|
2010-04-23 18:26:23 +02:00
|
|
|
return PE_ERROR;
|
|
|
|
}
|
2010-04-20 17:31:21 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-07 17:14:17 +02:00
|
|
|
return PE_OK;
|
2009-04-07 22:38:24 +02:00
|
|
|
}
|
|
|
|
|
2009-12-10 18:03:57 +01:00
|
|
|
## @apmethod int issuerLogout()
|
2009-04-08 18:31:13 +02:00
|
|
|
# TODO
|
2009-12-10 18:03:57 +01:00
|
|
|
# @return Lemonldap::NG::Portal error code
|
|
|
|
sub issuerLogout {
|
2009-04-08 18:31:13 +02:00
|
|
|
my $self = shift;
|
2010-03-26 14:56:37 +01:00
|
|
|
|
|
|
|
print STDERR "IssuerDBSAML: issuerLogout\n";
|
|
|
|
|
2009-12-10 18:03:57 +01:00
|
|
|
PE_OK;
|
2009-04-08 18:31:13 +02:00
|
|
|
}
|
|
|
|
|
2010-04-20 17:31:21 +02:00
|
|
|
## @pmethod int sendLogoutResponseAfterLogoutRequest(Lasso::Logout $logout,
|
|
|
|
# int $method string $relaystate)
|
|
|
|
# Send logout response issue from a logout request.
|
|
|
|
# @param $logout Lasso Logout object
|
|
|
|
# @param $method Method to use
|
|
|
|
# @param $relaystate The relay state
|
2010-04-23 18:26:23 +02:00
|
|
|
# @param $seconds Time to wait before redirecting, in seconds
|
2010-04-20 17:31:21 +02:00
|
|
|
# @return boolean False if failed.
|
|
|
|
sub sendLogoutResponseAfterLogoutRequest {
|
|
|
|
my $self = shift;
|
|
|
|
my $logout = shift;
|
|
|
|
my $method = shift;
|
|
|
|
my $relaystate = shift;
|
2010-04-23 18:26:23 +02:00
|
|
|
my $seconds = shift;
|
2010-04-20 17:31:21 +02:00
|
|
|
|
|
|
|
# Send response depending on request method
|
|
|
|
# HTTP-REDIRECT
|
|
|
|
if ( $method == Lasso::Constants::HTTP_METHOD_REDIRECT ) {
|
|
|
|
|
|
|
|
# Redirect user to response URL
|
|
|
|
my $slo_url = $logout->msg_url;
|
|
|
|
$self->lmLog( "Redirect user to $slo_url", 'debug' );
|
2010-04-23 18:26:23 +02:00
|
|
|
$self->{urldc} = $slo_url;
|
2010-04-20 17:31:21 +02:00
|
|
|
|
2010-04-23 17:18:08 +02:00
|
|
|
# Redirect immediately
|
2010-04-26 12:02:26 +02:00
|
|
|
if ( !$seconds ) {
|
2010-04-20 17:31:21 +02:00
|
|
|
|
2010-04-26 17:39:38 +02:00
|
|
|
$self->_subProcess(qw(autoRedirect));
|
|
|
|
$self->lmLog( "Logout response was not sent trough GET", 'error' );
|
2010-04-23 18:26:23 +02:00
|
|
|
return PE_ERROR;
|
2010-04-26 17:39:38 +02:00
|
|
|
|
|
|
|
}
|
2010-04-20 17:31:21 +02:00
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
# Redirect in few seconds
|
2010-04-23 17:18:08 +02:00
|
|
|
else {
|
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
return PE_INFO;
|
2010-04-23 17:18:08 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-20 17:31:21 +02:00
|
|
|
# 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->_subProcess(qw(autoPost));
|
|
|
|
|
|
|
|
# If we are here, there was a problem with POST response
|
|
|
|
$self->lmLog( "Logout response was not sent trough POST", 'error' );
|
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
return PE_ERROR;
|
2010-04-20 17:31:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# HTTP-SOAP
|
|
|
|
if ( $method == Lasso::Constants::HTTP_METHOD_SOAP ) {
|
|
|
|
|
|
|
|
my $slo_body = $logout->msg_body;
|
|
|
|
|
|
|
|
$self->lmLog( "SOAP response $slo_body", 'debug' );
|
|
|
|
|
|
|
|
$self->{SOAPMessage} = $slo_body;
|
|
|
|
|
|
|
|
$self->_subProcess(qw(returnSOAPMessage));
|
|
|
|
|
|
|
|
# If we are here, there was a problem with SOAP response
|
|
|
|
$self->lmLog( "Logout response was not sent trough SOAP", 'error' );
|
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
return PE_ERROR;
|
2010-04-20 17:31:21 +02:00
|
|
|
}
|
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
return PE_OK;
|
2010-04-20 17:31:21 +02:00
|
|
|
}
|
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
## @pmethod int sendLogoutRequestToServiceProviders(Lasso::Logout $logout)
|
|
|
|
# Send logout response issue from a logout request to all other service
|
|
|
|
# providers. If information have to be displayed to users, such as
|
|
|
|
# iframe to send HTTP-Redirect or HTTP-POST logout request, then
|
|
|
|
# $self->{_info} will be updated.
|
|
|
|
# @param $logout Lasso Logout object
|
|
|
|
# @return int Number of concerned providers.
|
2010-04-22 19:01:37 +02:00
|
|
|
sub sendLogoutRequestToServiceProviders {
|
|
|
|
my $self = shift;
|
|
|
|
my $logout = shift;
|
2010-04-26 17:39:38 +02:00
|
|
|
my $method = shift;
|
2010-04-22 19:01:37 +02:00
|
|
|
my $server = $self->{_lassoServer};
|
2010-04-23 18:26:23 +02:00
|
|
|
my $providerCount = 0;
|
|
|
|
my $info = '';
|
2010-04-22 19:01:37 +02:00
|
|
|
|
|
|
|
# Get EntityID
|
|
|
|
my $entityID = $logout->request->Issuer->content;
|
|
|
|
|
|
|
|
# Reset providerID into Lasso::Logout object
|
|
|
|
$self->resetProviderIdIndex($logout);
|
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
# Header of the block which will be displayed to the user, if needed.
|
2010-04-26 17:39:38 +02:00
|
|
|
$info .= &Lemonldap::NG::Portal::_i18n::msg(
|
|
|
|
PM_SAML_SPLOGOUT,
|
|
|
|
$ENV{HTTP_ACCEPT_LANGUAGE}
|
|
|
|
) . '<ul>';
|
2010-04-22 19:01:37 +02:00
|
|
|
|
|
|
|
# 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
|
2010-04-26 12:02:26 +02:00
|
|
|
next if ( $entityID =~ /^$providerID$/ );
|
2010-04-22 19:01:37 +02:00
|
|
|
|
|
|
|
# Find EntityID in SPList
|
|
|
|
unless ( defined $self->{_spList}->{$providerID} ) {
|
|
|
|
$self->lmLog( "$entityID does not match any known SP", 'error' );
|
2010-04-23 18:26:23 +02:00
|
|
|
next;
|
2010-04-22 19:01:37 +02:00
|
|
|
}
|
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
# Get SP Name from EntityID
|
|
|
|
my $providerName = $self->{_spList}->{$providerID}->{name};
|
|
|
|
|
2010-04-22 19:01:37 +02:00
|
|
|
# Get first HTTP method
|
|
|
|
my $protocolType = Lasso::Constants::MD_PROTOCOL_TYPE_SINGLE_LOGOUT;
|
2010-04-26 12:02:26 +02:00
|
|
|
|
2010-04-23 17:18:08 +02:00
|
|
|
#my $method =
|
|
|
|
# $self->getFirstHttpMethod( $server, $providerID, $protocolType );
|
2010-04-26 17:39:38 +02:00
|
|
|
if ( !$method ) {
|
|
|
|
$method = Lasso::Constants::HTTP_METHOD_REDIRECT;
|
|
|
|
}
|
2010-04-22 19:01:37 +02:00
|
|
|
|
|
|
|
# Initiate the logout request
|
2010-04-26 12:02:26 +02:00
|
|
|
unless ( $self->initLogoutRequest( $logout, $providerID, $method ) ) {
|
2010-04-22 19:01:37 +02:00
|
|
|
$self->lmLog( "Initiate logout request failed for $providerID",
|
|
|
|
'error' );
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Build request message
|
2010-04-26 12:02:26 +02:00
|
|
|
unless ( $self->buildLogoutRequestMsg($logout) ) {
|
2010-04-22 19:01:37 +02:00
|
|
|
$self->lmLog( "Build logout request failed for $providerID",
|
|
|
|
'error' );
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
2010-04-23 17:18:08 +02:00
|
|
|
$self->lmLog( "Send logout request to $providerID", 'debug' );
|
|
|
|
|
2010-04-22 19:01:37 +02:00
|
|
|
# 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;
|
|
|
|
|
2010-04-26 12:02:26 +02:00
|
|
|
$info .= '<li>'
|
|
|
|
. $providerName . '...'
|
|
|
|
. '<iframe src="'
|
|
|
|
. $slo_url
|
|
|
|
. '" alt="" marginwidth="0"'
|
2010-04-23 17:18:08 +02:00
|
|
|
. ' marginheight="0" scrolling="no" style="border: none"'
|
2010-04-23 18:26:23 +02:00
|
|
|
. ' width="0" height="0">'
|
2010-04-26 12:02:26 +02:00
|
|
|
. '<img src="'
|
|
|
|
. $slo_url
|
|
|
|
. '" width="0" height="0" />'
|
2010-04-22 19:01:37 +02:00
|
|
|
. '</iframe></li>';
|
2010-04-23 17:18:08 +02:00
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
$providerCount++;
|
|
|
|
|
2010-04-22 19:01:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# 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
|
2010-04-26 12:02:26 +02:00
|
|
|
$self->lmLog( "Message $samlID already used or expired",
|
|
|
|
'error' );
|
2010-04-22 19:01:37 +02:00
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-23 18:26:23 +02:00
|
|
|
# End of information block to be displayed to the user.
|
|
|
|
$info .= '</ul>';
|
|
|
|
|
2010-04-23 18:57:25 +02:00
|
|
|
# Print some information to the user. The URL to be redirected should
|
|
|
|
# not be send via a form (because it does not work all time).
|
2010-04-23 18:26:23 +02:00
|
|
|
if ($providerCount) {
|
|
|
|
$self->info($info);
|
2010-04-26 12:02:26 +02:00
|
|
|
$self->setHiddenFormValue( 'HttpRedirect', 'true' );
|
2010-04-26 15:10:04 +02:00
|
|
|
$self->setHiddenFormValue( 'HideSubmitButton', 'true' );
|
2010-04-23 18:26:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $providerCount;
|
2010-04-22 19:01:37 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-04-07 22:38:24 +02:00
|
|
|
1;
|
2009-12-10 18:03:57 +01:00
|
|
|
|
2009-04-07 22:38:24 +02:00
|
|
|
__END__
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
2010-01-03 09:09:59 +01:00
|
|
|
=encoding utf8
|
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
Lemonldap::NG::Portal::IssuerDBSAML - SAML IssuerDB for LemonLDAP::NG
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
use Lemonldap::NG::Portal::SharedConf;
|
|
|
|
|
|
|
|
my $portal = Lemonldap::NG::Portal::SharedConf->new({
|
|
|
|
issuerDB => SAML,
|
|
|
|
});
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
SAML IssuerDB for LemonLDAP::NG
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
L<Lemonldap::NG::Portal>
|
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
2009-12-13 16:40:33 +01:00
|
|
|
Clément Oudot, E<lt>coudot@linagora.comE<gt>
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
|
2009-12-13 16:40:33 +01:00
|
|
|
Copyright (C) 2009 by Clément Oudot
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.10.0 or,
|
|
|
|
at your option, any later version of Perl 5 you may have available.
|
|
|
|
|
|
|
|
=cut
|