2009-04-07 22:38:24 +02:00
|
|
|
## @file
|
|
|
|
# Common SAML functions
|
|
|
|
|
|
|
|
## @class
|
|
|
|
# Common SAML functions
|
|
|
|
package Lemonldap::NG::Portal::_SAML;
|
|
|
|
|
|
|
|
use strict;
|
2010-03-25 12:01:32 +01:00
|
|
|
use Lemonldap::NG::Common::Conf::SAML::Metadata;
|
2010-02-05 18:18:09 +01:00
|
|
|
use XML::Simple;
|
2010-02-12 11:53:43 +01:00
|
|
|
use MIME::Base64;
|
2010-04-28 19:16:38 +02:00
|
|
|
use String::Random;
|
2010-02-24 16:24:54 +01:00
|
|
|
use LWP::UserAgent; # SOAP call
|
|
|
|
use HTTP::Request; # SOAP call
|
2010-04-08 11:43:28 +02:00
|
|
|
use POSIX; # Convert SAML2 date into timestamp
|
2010-05-12 14:46:47 +02:00
|
|
|
use Time::Local; # Convert SAML2 date into timestamp
|
2010-04-28 16:56:36 +02:00
|
|
|
use Encode; # Encode attribute values
|
2010-01-29 11:44:56 +01:00
|
|
|
|
2010-05-02 15:30:04 +02:00
|
|
|
our $VERSION = '0.01';
|
2010-06-25 17:38:14 +02:00
|
|
|
our $samlCache;
|
2009-04-07 22:38:24 +02:00
|
|
|
|
2010-02-08 11:06:21 +01:00
|
|
|
BEGIN {
|
|
|
|
|
|
|
|
# Load Glib if available
|
|
|
|
eval 'use Glib;';
|
|
|
|
if ($@) {
|
|
|
|
print STDERR
|
|
|
|
"Glib Lasso messages will not be catched (require Glib module)\n";
|
|
|
|
eval "use constant GLIB => 0";
|
|
|
|
}
|
|
|
|
else {
|
2010-02-08 11:16:28 +01:00
|
|
|
eval "use constant GLIB => 1";
|
2010-02-08 11:06:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Load Lasso.pm
|
|
|
|
eval 'use Lasso;';
|
|
|
|
if ($@) {
|
|
|
|
print STDERR "Lasso.pm not loaded :$@";
|
|
|
|
eval 'use constant LASSO => 0;use constant BADLASSO => 0;';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
no strict 'subs';
|
|
|
|
eval 'use constant LASSO => 1';
|
2010-02-08 18:24:45 +01:00
|
|
|
|
|
|
|
# Check Lasso version >= 2.2.91
|
2010-02-08 11:06:21 +01:00
|
|
|
my $lasso_check_version_mode = Lasso::Constants::CHECK_VERSION_NUMERIC;
|
|
|
|
my $check_version =
|
|
|
|
Lasso::check_version( 2, 2, 91, $lasso_check_version_mode );
|
|
|
|
unless ($check_version) {
|
|
|
|
eval 'use constant BADLASSO => 1';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
eval 'use constant BADLASSO => 0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-01-29 11:44:56 +01:00
|
|
|
## @method boolean loadLasso()
|
|
|
|
# Load Lasso module
|
|
|
|
# @return boolean result
|
|
|
|
sub loadLasso {
|
|
|
|
my $self = shift;
|
|
|
|
|
2010-02-01 16:24:56 +01:00
|
|
|
# Catch GLib Lasso messages (require Glib)
|
2010-02-08 11:06:21 +01:00
|
|
|
if (GLIB) {
|
2010-02-01 16:24:56 +01:00
|
|
|
Glib::Log->set_handler(
|
|
|
|
"Lasso",
|
|
|
|
[qw/ error critical warning message info debug /],
|
|
|
|
sub {
|
|
|
|
$self->lmLog( $_[0] . " error " . $_[1] . ": " . $_[2],
|
|
|
|
'debug' );
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
2010-02-08 18:24:45 +01:00
|
|
|
|
2010-02-08 11:06:21 +01:00
|
|
|
unless (LASSO) {
|
|
|
|
$self->lmLog( "Module Lasso not loaded (see bellow)", 'error' );
|
2010-01-29 11:44:56 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-08 11:06:21 +01:00
|
|
|
if (BADLASSO) {
|
2010-02-01 15:01:28 +01:00
|
|
|
$self->lmLog( 'Lasso version >= 2.2.91 required', 'error' );
|
2010-01-29 18:33:35 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2010-02-08 18:24:45 +01:00
|
|
|
|
2010-01-29 18:33:35 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-06-25 17:38:14 +02:00
|
|
|
## @method boolean loadService(boolean no_cache)
|
2010-03-26 10:35:31 +01:00
|
|
|
# Load SAML service by creating a Lasso::Server
|
2010-06-25 17:38:14 +02:00
|
|
|
# @param no_cache Disable cache use
|
2010-03-25 12:01:32 +01:00
|
|
|
# @return boolean result
|
|
|
|
sub loadService {
|
2010-06-25 17:38:14 +02:00
|
|
|
my ( $self, $no_cache ) = splice @_;
|
2010-03-25 12:01:32 +01:00
|
|
|
|
|
|
|
# Load Lasso
|
|
|
|
return 0 unless $self->loadLasso();
|
|
|
|
|
2010-06-25 17:38:14 +02:00
|
|
|
# Try to restore server from cache
|
|
|
|
unless ($no_cache) {
|
|
|
|
|
|
|
|
# Check if Lasso::Server is present in self
|
|
|
|
return 1 if $self->{_lassoServer};
|
|
|
|
|
|
|
|
# Check if Lasso::Server can be restored from cache
|
|
|
|
if ( $samlCache->{_lassoServerDump} ) {
|
|
|
|
$self->lmLog( "Restore server from cache", 'debug' );
|
|
|
|
eval {
|
|
|
|
$self->{_lassoServer} = Lasso::Server::new_from_dump(
|
|
|
|
$samlCache->{_lassoServerDump} );
|
|
|
|
};
|
|
|
|
return 1 if $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-09 10:42:30 +02:00
|
|
|
# Check presence of private and public key in configuration
|
2010-09-01 14:56:15 +02:00
|
|
|
my $publicKeySig = $self->{samlServicePublicKeySig};
|
|
|
|
my $privateKeySig = $self->{samlServicePrivateKeySig};
|
2010-07-05 13:50:12 +02:00
|
|
|
my $privateKeySigPwd = $self->{samlServicePrivateKeySigPwd};
|
2010-09-01 14:56:15 +02:00
|
|
|
my $privateKeyEnc = $self->{samlServicePrivateKeyEnc};
|
2010-07-05 13:50:12 +02:00
|
|
|
my $privateKeyEncPwd = $self->{samlServicePrivateKeyEncPwd};
|
2010-06-09 10:42:30 +02:00
|
|
|
unless ( $privateKeySig and $publicKeySig ) {
|
|
|
|
$self->lmLog( "SAML private and public key not found in configuration",
|
|
|
|
'error' );
|
2010-03-25 12:01:32 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2010-06-11 12:17:43 +02:00
|
|
|
unless ($privateKeyEnc) {
|
|
|
|
$self->lmLog(
|
|
|
|
"SAML private encryption key not found in configuration, "
|
|
|
|
. "use private signature key",
|
|
|
|
'debug'
|
|
|
|
);
|
2010-09-01 14:56:15 +02:00
|
|
|
$privateKeyEnc = $privateKeySig;
|
2010-07-05 13:50:12 +02:00
|
|
|
$privateKeyEncPwd = $privateKeySigPwd;
|
2010-06-09 10:42:30 +02:00
|
|
|
}
|
2010-03-25 12:01:32 +01:00
|
|
|
|
|
|
|
# Get metadata from configuration
|
|
|
|
$self->lmLog( "Get Metadata for this service", 'debug' );
|
|
|
|
my $service_metadata = Lemonldap::NG::Common::Conf::SAML::Metadata->new();
|
|
|
|
|
|
|
|
# Create Lasso server with service metadata
|
|
|
|
my $server = $self->createServer(
|
|
|
|
$service_metadata->serviceToXML(
|
|
|
|
$ENV{DOCUMENT_ROOT} . "/skins/common/saml2-metadata.tpl", $self
|
|
|
|
),
|
2010-06-11 12:17:43 +02:00
|
|
|
$privateKeySig,
|
2010-07-05 13:50:12 +02:00
|
|
|
$privateKeySigPwd,
|
|
|
|
$privateKeyEnc,
|
|
|
|
$privateKeyEncPwd,
|
2010-03-25 12:01:32 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
# Log
|
|
|
|
unless ($server) {
|
|
|
|
$self->lmLog( 'Unable to create Lasso server', 'error' );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
$self->lmLog( "Service created", 'debug' );
|
|
|
|
|
|
|
|
# Store Lasso::Server object
|
|
|
|
$self->{_lassoServer} = $server;
|
2010-06-25 17:38:14 +02:00
|
|
|
$samlCache->{_lassoServerDump} = $server->dump unless $no_cache;
|
2010-03-25 12:01:32 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-06-25 17:38:14 +02:00
|
|
|
## @method boolean loadIDPs(boolean no_cache)
|
2010-03-25 12:01:32 +01:00
|
|
|
# Load SAML identity providers
|
2010-06-25 17:38:14 +02:00
|
|
|
# @param no_cache Disable cache use
|
2010-03-25 12:01:32 +01:00
|
|
|
# @return boolean result
|
|
|
|
sub loadIDPs {
|
2010-06-25 17:38:14 +02:00
|
|
|
my ( $self, $no_cache ) = splice @_;
|
2010-03-25 12:01:32 +01:00
|
|
|
|
|
|
|
# Check if SAML service is loaded
|
|
|
|
return 0 unless $self->{_lassoServer};
|
|
|
|
|
2010-06-25 17:38:14 +02:00
|
|
|
# Check cache
|
|
|
|
unless ($no_cache) {
|
|
|
|
if ( $samlCache->{_idpList} ) {
|
|
|
|
$self->lmLog( "Load IDPs from cache", 'debug' );
|
|
|
|
$self->{_idpList} = $samlCache->{_idpList};
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-25 12:01:32 +01:00
|
|
|
# Check presence of at least one identity provider in configuration
|
|
|
|
unless ( $self->{samlIDPMetaDataXML}
|
|
|
|
and keys %{ $self->{samlIDPMetaDataXML} } )
|
|
|
|
{
|
2010-05-26 17:32:09 +02:00
|
|
|
$self->lmLog( "No IDP found in configuration", 'warn' );
|
2010-03-25 12:01:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Load identity provider metadata
|
|
|
|
# IDP metadata are listed in $self->{samlIDPMetaDataXML}
|
|
|
|
# Each key is the IDP name
|
|
|
|
# Build IDP list for later use in extractFormInfo
|
2010-03-25 15:44:38 +01:00
|
|
|
$self->{_idpList} = ();
|
2010-03-25 12:01:32 +01:00
|
|
|
foreach ( keys %{ $self->{samlIDPMetaDataXML} } ) {
|
|
|
|
|
|
|
|
$self->lmLog( "Get Metadata for IDP $_", 'debug' );
|
|
|
|
|
2010-06-25 15:51:09 +02:00
|
|
|
my $idp_metadata =
|
|
|
|
$self->{samlIDPMetaDataXML}->{$_}->{samlIDPMetaDataXML};
|
|
|
|
|
|
|
|
# Check metadata format
|
|
|
|
if ( ref $idp_metadata eq "HASH" ) {
|
|
|
|
$self->abort(
|
|
|
|
"Metadata for IDP $_ is in old format. Please reload them from Manager"
|
|
|
|
);
|
2010-03-25 12:01:32 +01:00
|
|
|
}
|
|
|
|
|
2010-06-28 11:11:59 +02:00
|
|
|
if ( $self->{samlMetadataForceUTF8} ) {
|
|
|
|
$idp_metadata = encode( "utf8", $idp_metadata );
|
|
|
|
}
|
|
|
|
|
2010-03-25 12:01:32 +01:00
|
|
|
# Add this IDP to Lasso::Server
|
2010-06-25 15:51:09 +02:00
|
|
|
my $result = $self->addIDP( $self->{_lassoServer}, $idp_metadata );
|
2010-03-25 12:01:32 +01:00
|
|
|
|
|
|
|
unless ($result) {
|
|
|
|
$self->lmLog( "Fail to use IDP $_ Metadata", 'error' );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Store IDP entityID and Organization Name
|
2010-06-25 15:51:09 +02:00
|
|
|
my ($entityID) = ( $idp_metadata =~ /entityID="(.+?)"/i );
|
2010-04-01 11:55:33 +02:00
|
|
|
my $name =
|
|
|
|
$self->getOrganizationName( $self->{_lassoServer}, $entityID )
|
2010-03-25 12:01:32 +01:00
|
|
|
|| ucfirst($_);
|
2010-04-30 16:55:40 +02:00
|
|
|
$self->{_idpList}->{$entityID}->{confKey} = $_;
|
|
|
|
$self->{_idpList}->{$entityID}->{name} = $name;
|
2010-03-25 12:01:32 +01:00
|
|
|
|
2010-06-04 17:54:52 +02:00
|
|
|
# Set encryption mode
|
|
|
|
my $encryption_mode =
|
|
|
|
$self->{samlIDPMetaDataOptions}->{$_}
|
|
|
|
->{samlIDPMetaDataOptionsEncryptionMode};
|
|
|
|
my $lasso_encryption_mode = $self->getEncryptionMode($encryption_mode);
|
|
|
|
|
|
|
|
unless (
|
|
|
|
$self->setProviderEncryptionMode(
|
|
|
|
$self->{_lassoServer}->get_provider($entityID),
|
|
|
|
$lasso_encryption_mode
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
$self->lmLog(
|
|
|
|
"Unable to set encryption mode $encryption_mode on IDP $_",
|
|
|
|
'error' );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Set encryption mode $encryption_mode on IDP $_",
|
|
|
|
'debug' );
|
|
|
|
|
2010-03-25 12:01:32 +01:00
|
|
|
$self->lmLog( "IDP $_ added", 'debug' );
|
|
|
|
}
|
|
|
|
|
2010-06-25 17:38:14 +02:00
|
|
|
# Cache Lasso::Server
|
|
|
|
$samlCache->{_idpList} = $self->{_idpList} unless $no_cache;
|
|
|
|
$samlCache->{_lassoServerDump} = $self->{_lassoServer}->dump
|
|
|
|
unless $no_cache;
|
|
|
|
|
2010-03-25 12:01:32 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-06-25 17:38:14 +02:00
|
|
|
## @method boolean loadSPs(boolean no_cache)
|
2010-03-25 12:01:32 +01:00
|
|
|
# Load SAML service providers
|
2010-06-25 17:38:14 +02:00
|
|
|
# @param no_cache Disable cache use
|
2010-03-25 12:01:32 +01:00
|
|
|
# @return boolean result
|
|
|
|
sub loadSPs {
|
2010-06-25 17:38:14 +02:00
|
|
|
my ( $self, $no_cache ) = splice @_;
|
2010-03-25 12:24:52 +01:00
|
|
|
|
|
|
|
# Check if SAML service is loaded
|
|
|
|
return 0 unless $self->{_lassoServer};
|
|
|
|
|
2010-06-25 17:38:14 +02:00
|
|
|
# Check cache
|
|
|
|
unless ($no_cache) {
|
|
|
|
if ( $samlCache->{_spList} ) {
|
|
|
|
$self->lmLog( "Load SPs from cache", 'debug' );
|
|
|
|
$self->{_spList} = $samlCache->{_spList};
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-25 12:24:52 +01:00
|
|
|
# Check presence of at least one service provider in configuration
|
|
|
|
unless ( $self->{samlSPMetaDataXML}
|
|
|
|
and keys %{ $self->{samlSPMetaDataXML} } )
|
|
|
|
{
|
2010-05-26 17:32:09 +02:00
|
|
|
$self->lmLog( "No SP found in configuration", 'warn' );
|
2010-03-25 12:24:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Load service provider metadata
|
|
|
|
# SP metadata are listed in $self->{samlSPMetaDataXML}
|
|
|
|
# Each key is the SP name
|
|
|
|
# Build SP list for later use in extractFormInfo
|
2010-03-25 15:44:38 +01:00
|
|
|
$self->{_spList} = ();
|
2010-03-25 12:24:52 +01:00
|
|
|
foreach ( keys %{ $self->{samlSPMetaDataXML} } ) {
|
|
|
|
|
|
|
|
$self->lmLog( "Get Metadata for SP $_", 'debug' );
|
|
|
|
|
2010-06-25 15:51:09 +02:00
|
|
|
my $sp_metadata = $self->{samlSPMetaDataXML}->{$_}->{samlSPMetaDataXML};
|
|
|
|
|
|
|
|
# Check metadata format
|
|
|
|
if ( ref $sp_metadata eq "HASH" ) {
|
|
|
|
$self->abort(
|
|
|
|
"Metadata for SP $_ is in old format. Please reload them from Manager"
|
|
|
|
);
|
2010-03-25 12:24:52 +01:00
|
|
|
}
|
|
|
|
|
2010-06-28 11:11:59 +02:00
|
|
|
if ( $self->{samlMetadataForceUTF8} ) {
|
|
|
|
$sp_metadata = encode( "utf8", $sp_metadata );
|
|
|
|
}
|
|
|
|
|
2010-03-25 12:24:52 +01:00
|
|
|
# Add this SP to Lasso::Server
|
2010-06-25 15:51:09 +02:00
|
|
|
my $result = $self->addSP( $self->{_lassoServer}, $sp_metadata );
|
2010-03-25 12:24:52 +01:00
|
|
|
|
|
|
|
unless ($result) {
|
|
|
|
$self->lmLog( "Fail to use SP $_ Metadata", 'error' );
|
2010-04-14 17:37:57 +02:00
|
|
|
return 0;
|
2010-03-25 12:24:52 +01:00
|
|
|
}
|
|
|
|
|
2010-03-26 10:35:31 +01:00
|
|
|
# Store SP entityID and Organization Name
|
2010-06-25 15:51:09 +02:00
|
|
|
my ($entityID) = ( $sp_metadata =~ /entityID="(.+?)"/i );
|
2010-04-01 11:55:33 +02:00
|
|
|
my $name =
|
|
|
|
$self->getOrganizationName( $self->{_lassoServer}, $entityID )
|
2010-03-25 12:24:52 +01:00
|
|
|
|| ucfirst($_);
|
2010-04-15 16:42:17 +02:00
|
|
|
$self->{_spList}->{$entityID}->{confKey} = $_;
|
|
|
|
$self->{_spList}->{$entityID}->{name} = $name;
|
2010-03-25 12:24:52 +01:00
|
|
|
|
2010-06-04 17:54:52 +02:00
|
|
|
# Set encryption mode
|
|
|
|
my $encryption_mode =
|
|
|
|
$self->{samlSPMetaDataOptions}->{$_}
|
|
|
|
->{samlSPMetaDataOptionsEncryptionMode};
|
|
|
|
my $lasso_encryption_mode = $self->getEncryptionMode($encryption_mode);
|
|
|
|
|
|
|
|
unless (
|
|
|
|
$self->setProviderEncryptionMode(
|
|
|
|
$self->{_lassoServer}->get_provider($entityID),
|
|
|
|
$lasso_encryption_mode
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
$self->lmLog(
|
|
|
|
"Unable to set encryption mode $encryption_mode on SP $_",
|
|
|
|
'error' );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Set encryption mode $encryption_mode on SP $_",
|
|
|
|
'debug' );
|
|
|
|
|
2010-03-25 12:24:52 +01:00
|
|
|
$self->lmLog( "SP $_ added", 'debug' );
|
|
|
|
}
|
|
|
|
|
2010-06-25 17:38:14 +02:00
|
|
|
# Cache Lasso::Server
|
|
|
|
$samlCache->{_spList} = $self->{_spList} unless $no_cache;
|
|
|
|
$samlCache->{_lassoServerDump} = $self->{_lassoServer}->dump
|
|
|
|
unless $no_cache;
|
|
|
|
|
2010-03-25 12:24:52 +01:00
|
|
|
return 1;
|
2010-03-25 12:01:32 +01:00
|
|
|
}
|
|
|
|
|
2010-04-30 16:55:40 +02:00
|
|
|
## @method array checkMessage(string url, string request_method, string content_type, string profile_type)
|
2010-03-26 17:02:27 +01:00
|
|
|
# Check SAML requests and responses
|
2010-04-02 16:47:17 +02:00
|
|
|
# @param url
|
|
|
|
# @param request_method
|
|
|
|
# @param content_type
|
|
|
|
# @param profile_type login or logout
|
|
|
|
# @return ( $request, $response, $method, $relaystate, $artifact )
|
2010-03-26 17:02:27 +01:00
|
|
|
sub checkMessage {
|
2010-05-02 13:37:25 +02:00
|
|
|
my ( $self, $url, $request_method, $content_type, $profile_type ) =
|
|
|
|
splice @_;
|
|
|
|
$profile_type ||= "login";
|
|
|
|
my ( $request, $response, $message, $method, $relaystate, $artifact );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
|
|
|
# Check if SAML service is loaded
|
2010-04-02 16:47:17 +02:00
|
|
|
return ( $request, $response, $method, $relaystate, $artifact )
|
2010-03-26 17:02:27 +01:00
|
|
|
unless $self->{_lassoServer};
|
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
# 1. Get hidden fields
|
|
|
|
$request = $self->getHiddenFormValue('SAMLRequest');
|
|
|
|
$response = $self->getHiddenFormValue('SAMLResponse');
|
|
|
|
$method = $self->getHiddenFormValue('Method');
|
|
|
|
$relaystate = $self->getHiddenFormValue('RelayState');
|
|
|
|
$artifact = $self->getHiddenFormValue('SAMLart');
|
|
|
|
|
|
|
|
# 2. If no hidden fields, check HTTP request contents
|
|
|
|
unless ( $request or $response ) {
|
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Create Profile object
|
|
|
|
my $profile;
|
|
|
|
$profile = $self->createLogin( $self->{_lassoServer} )
|
|
|
|
if ( $profile_type eq "login" );
|
|
|
|
$profile = $self->createLogout( $self->{_lassoServer} )
|
|
|
|
if ( $profile_type eq "logout" );
|
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
# Get relayState
|
|
|
|
$relaystate = $self->param('RelayState');
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
# 2.1. HTTP REDIRECT
|
2010-04-14 17:37:57 +02:00
|
|
|
if ( $request_method =~ /^GET$/ ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
$method = Lasso::Constants::HTTP_METHOD_REDIRECT;
|
|
|
|
$self->lmLog( "SAML method: HTTP-REDIRECT", 'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
if ( $self->param('SAMLResponse') ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Response in query string
|
|
|
|
$response = $self->query_string();
|
2010-04-07 12:11:21 +02:00
|
|
|
$self->lmLog( "HTTP-REDIRECT: SAML Response $response",
|
|
|
|
'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
if ( $self->param('SAMLRequest') ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Request in query string
|
|
|
|
$request = $self->query_string();
|
|
|
|
$self->lmLog( "HTTP-REDIRECT: SAML Request $request", 'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
if ( $self->param('SAMLart') ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Artifact in query string
|
|
|
|
$artifact = $self->query_string();
|
2010-04-07 12:11:21 +02:00
|
|
|
$self->lmLog( "HTTP-REDIRECT: SAML Artifact $artifact",
|
|
|
|
'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Resolve Artifact
|
|
|
|
$method = Lasso::Constants::HTTP_METHOD_ARTIFACT_GET;
|
2010-04-30 16:55:40 +02:00
|
|
|
$message =
|
2010-04-14 17:37:57 +02:00
|
|
|
$self->resolveArtifact( $profile, $artifact, $method );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Request or response ?
|
|
|
|
if ( $message =~ /samlp:response/i ) {
|
|
|
|
$response = $message;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$request = $message;
|
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
}
|
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
# 2.2. HTTP POST AND SOAP
|
2010-04-14 17:37:57 +02:00
|
|
|
elsif ( $request_method =~ /^POST$/ ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
# 2.2.1. POST
|
2010-04-14 17:37:57 +02:00
|
|
|
if ( $content_type !~ /xml/ ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
$method = Lasso::Constants::HTTP_METHOD_POST;
|
|
|
|
$self->lmLog( "SAML method: HTTP-POST", 'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
if ( $self->param('SAMLResponse') ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Response in body part
|
|
|
|
$response = $self->param('SAMLResponse');
|
2010-04-07 12:11:21 +02:00
|
|
|
$self->lmLog( "HTTP-POST: SAML Response $response",
|
|
|
|
'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-05-02 13:37:25 +02:00
|
|
|
elsif ( $self->param('SAMLRequest') ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Request in body part
|
|
|
|
$request = $self->param('SAMLRequest');
|
|
|
|
$self->lmLog( "HTTP-POST: SAML Request $request", 'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-05-02 13:37:25 +02:00
|
|
|
elsif ( $self->param('SAMLart') ) {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Artifact in SAMLart param
|
|
|
|
$artifact = $self->param('SAMLart');
|
2010-05-31 17:46:41 +02:00
|
|
|
$self->lmLog( "HTTP-POST: SAML Artifact $artifact",
|
2010-04-14 17:37:57 +02:00
|
|
|
'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# Resolve Artifact
|
|
|
|
$method = Lasso::Constants::HTTP_METHOD_ARTIFACT_POST;
|
2010-04-30 16:55:40 +02:00
|
|
|
$message =
|
2010-04-14 17:37:57 +02:00
|
|
|
$self->resolveArtifact( $profile, $artifact, $method );
|
|
|
|
|
|
|
|
# Request or response ?
|
|
|
|
if ( $message =~ /samlp:response/i ) {
|
|
|
|
$response = $message;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$request = $message;
|
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
# 2.2.2. SOAP
|
2010-04-14 17:37:57 +02:00
|
|
|
else {
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
$method = Lasso::Constants::HTTP_METHOD_SOAP;
|
|
|
|
$self->lmLog( "SAML method: HTTP-SOAP", 'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
# SOAP is always a request
|
|
|
|
$request = $self->param('POSTDATA');
|
|
|
|
$self->lmLog( "HTTP-SOAP: SAML Request $request", 'debug' );
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-14 17:37:57 +02:00
|
|
|
}
|
2010-03-26 17:02:27 +01:00
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog( "Keep values from hidden fields", 'debug' );
|
|
|
|
}
|
2010-04-02 17:28:29 +02:00
|
|
|
|
|
|
|
# 3. Backup values into hidden form values, if process is interrupted
|
|
|
|
# later in LemonLDAP::NG
|
|
|
|
|
2010-04-07 12:11:21 +02:00
|
|
|
$self->setHiddenFormValue( 'SAMLRequest', $request );
|
|
|
|
$self->setHiddenFormValue( 'SAMLResponse', $response );
|
|
|
|
$self->setHiddenFormValue( 'Method', $method );
|
|
|
|
$self->setHiddenFormValue( 'RelayState', $relaystate );
|
|
|
|
$self->setHiddenFormValue( 'SAMLart', $artifact );
|
2010-04-02 17:28:29 +02:00
|
|
|
|
2010-04-30 16:55:40 +02:00
|
|
|
# 4. Return values
|
2010-03-26 17:02:27 +01:00
|
|
|
return ( $request, $response, $method, $relaystate, $artifact ? 1 : 0 );
|
|
|
|
}
|
|
|
|
|
2010-01-29 18:33:35 +01:00
|
|
|
## @method boolean checkLassoError(Lasso::Error error, string level)
|
|
|
|
# Log Lasso error code and message if this is actually a Lasso::Error with code > 0
|
|
|
|
# @param Lasso::Error Lasso error object
|
|
|
|
# @param string optional log level (debug by default)
|
|
|
|
# @return 1 if no error
|
|
|
|
sub checkLassoError {
|
2010-02-08 11:06:21 +01:00
|
|
|
my ( $self, $error, $level ) = splice @_;
|
2010-02-12 15:26:45 +01:00
|
|
|
$level ||= 'debug';
|
2010-01-29 18:33:35 +01:00
|
|
|
|
2010-02-03 11:59:53 +01:00
|
|
|
# If $error is not a Lasso::Error object, display error string
|
|
|
|
unless ( ref($error) and $error->isa("Lasso::Error") ) {
|
|
|
|
return 1 unless $error;
|
|
|
|
$self->lmLog( "Lasso error: $error", $level );
|
|
|
|
return 0;
|
|
|
|
}
|
2010-01-29 18:33:35 +01:00
|
|
|
|
2010-02-03 11:59:53 +01:00
|
|
|
# Else check error code and error message
|
2010-01-29 18:33:35 +01:00
|
|
|
if ( $error->{code} ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Lasso error code " . $error->{code} . ": " . $error->{message},
|
|
|
|
$level );
|
|
|
|
return 0;
|
|
|
|
}
|
2010-01-29 11:44:56 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-06-09 10:42:30 +02:00
|
|
|
## @method Lasso::Server createServer(string metadata, string private_key, string private_key_password, string private_key_enc, string private_key_enc_password, string certificate)
|
2010-01-29 18:33:35 +01:00
|
|
|
# Load service metadata and create Lasso::Server object
|
2010-02-01 15:01:28 +01:00
|
|
|
# @param string metadata
|
2010-02-03 11:59:53 +01:00
|
|
|
# @param string private key
|
2010-02-01 15:01:28 +01:00
|
|
|
# @param string optional private key password
|
2010-06-09 10:42:30 +02:00
|
|
|
# @param string optional private key for encryption
|
|
|
|
# @param string optional private key password for encryption
|
2010-02-01 15:01:28 +01:00
|
|
|
# @param string optional certificate
|
2010-01-29 18:33:35 +01:00
|
|
|
# @return Lasso::Server object
|
|
|
|
sub createServer {
|
2010-06-11 12:17:43 +02:00
|
|
|
my ( $self, $metadata, $private_key, $private_key_password,
|
|
|
|
$private_key_enc, $private_key_enc_password, $certificate )
|
|
|
|
= splice @_;
|
2010-06-01 14:23:11 +02:00
|
|
|
my $server;
|
2010-01-29 18:33:35 +01:00
|
|
|
|
2010-02-03 11:59:53 +01:00
|
|
|
eval {
|
|
|
|
$server = Lasso::Server::new_from_buffers( $metadata, $private_key,
|
2010-02-08 11:06:21 +01:00
|
|
|
$private_key_password, $certificate );
|
2010-06-11 12:17:43 +02:00
|
|
|
|
2010-07-05 13:50:12 +02:00
|
|
|
# Set private key for encryption
|
2010-06-11 12:17:43 +02:00
|
|
|
if ($private_key_enc) {
|
2010-07-05 13:50:12 +02:00
|
|
|
Lasso::Server::set_encryption_private_key_with_password( $server,
|
|
|
|
$private_key_enc, $private_key_enc_password );
|
2010-06-09 10:42:30 +02:00
|
|
|
}
|
2010-02-03 11:59:53 +01:00
|
|
|
};
|
2010-01-29 18:33:35 +01:00
|
|
|
|
2010-02-08 18:24:45 +01:00
|
|
|
if ($@) {
|
2010-02-08 11:16:28 +01:00
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
2010-01-29 18:33:35 +01:00
|
|
|
|
|
|
|
return $server;
|
|
|
|
}
|
|
|
|
|
2010-02-01 18:07:40 +01:00
|
|
|
## @method boolean addIDP(Lasso::Server server, string metadata, string public_key, string ca_cert_chain)
|
|
|
|
# Add IDP to an existing Lasso::Server
|
|
|
|
# @param Lasso::Server Lasso::Server object
|
|
|
|
# @param string metadata IDP metadata
|
|
|
|
# @param string optional public key
|
|
|
|
# @param string optional ca cert chain
|
|
|
|
# @return boolean result
|
|
|
|
sub addIDP {
|
2010-02-08 11:06:21 +01:00
|
|
|
my ( $self, $server, $metadata, $public_key, $ca_cert_chain ) = splice @_;
|
2010-02-01 18:07:40 +01:00
|
|
|
|
|
|
|
return 0 unless ( $server->isa("Lasso::Server") and defined $metadata );
|
|
|
|
|
|
|
|
return $self->addProvider( $server, Lasso::Constants::PROVIDER_ROLE_IDP,
|
|
|
|
$metadata, $public_key, $ca_cert_chain );
|
|
|
|
}
|
|
|
|
|
2010-03-25 12:24:52 +01:00
|
|
|
## @method boolean addSP(Lasso::Server server, string metadata, string public_key, string ca_cert_chain)
|
|
|
|
# Add SP to an existing Lasso::Server
|
|
|
|
# @param Lasso::Server Lasso::Server object
|
|
|
|
# @param string metadata SP metadata
|
|
|
|
# @param string optional public key
|
|
|
|
# @param string optional ca cert chain
|
|
|
|
# @return boolean result
|
|
|
|
sub addSP {
|
|
|
|
my ( $self, $server, $metadata, $public_key, $ca_cert_chain ) = splice @_;
|
|
|
|
|
|
|
|
return 0 unless ( $server->isa("Lasso::Server") and defined $metadata );
|
|
|
|
|
2010-03-25 15:44:38 +01:00
|
|
|
return $self->addProvider( $server, Lasso::Constants::PROVIDER_ROLE_SP,
|
|
|
|
$metadata, $public_key, $ca_cert_chain );
|
2010-03-25 12:24:52 +01:00
|
|
|
}
|
|
|
|
|
2010-06-01 14:23:11 +02:00
|
|
|
## @method boolean addAA(Lasso::Server server, string metadata, string public_key, string ca_cert_chain)
|
|
|
|
# Add Attribute Authority to an existing Lasso::Server
|
|
|
|
# @param Lasso::Server Lasso::Server object
|
|
|
|
# @param string metadata AA metadata
|
|
|
|
# @param string optional public key
|
|
|
|
# @param string optional ca cert chain
|
|
|
|
# @return boolean result
|
|
|
|
sub addAA {
|
|
|
|
my ( $self, $server, $metadata, $public_key, $ca_cert_chain ) = splice @_;
|
|
|
|
|
|
|
|
return 0 unless ( $server->isa("Lasso::Server") and defined $metadata );
|
|
|
|
|
|
|
|
return $self->addProvider( $server,
|
|
|
|
Lasso::Constants::PROVIDER_ROLE_ATTRIBUTE_AUTHORITY,
|
|
|
|
$metadata, $public_key, $ca_cert_chain );
|
|
|
|
}
|
|
|
|
|
2010-02-01 18:07:40 +01:00
|
|
|
## @method boolean addProvider(Lasso::Server server, int role, string metadata, string public_key, string ca_cert_chain)
|
|
|
|
# Add provider to an existing Lasso::Server
|
|
|
|
# @param Lasso::Server Lasso::Server object
|
|
|
|
# @param int role (IDP, SP or Both)
|
|
|
|
# @param string metadata IDP metadata
|
|
|
|
# @param string optional public key
|
|
|
|
# @param string optional ca cert chain
|
|
|
|
# @return boolean result
|
|
|
|
sub addProvider {
|
2010-02-08 11:06:21 +01:00
|
|
|
my ( $self, $server, $role, $metadata, $public_key, $ca_cert_chain ) =
|
|
|
|
splice @_;
|
2010-02-01 18:07:40 +01:00
|
|
|
|
|
|
|
return 0
|
|
|
|
unless ( $server->isa("Lasso::Server")
|
|
|
|
and defined $role
|
|
|
|
and defined $metadata );
|
|
|
|
|
|
|
|
eval {
|
2010-02-02 22:55:25 +01:00
|
|
|
Lasso::Server::add_provider_from_buffer( $server, $role, $metadata,
|
2010-02-01 18:07:40 +01:00
|
|
|
$public_key, $ca_cert_chain );
|
|
|
|
};
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
|
|
|
|
}
|
2010-02-05 18:18:09 +01:00
|
|
|
|
|
|
|
## @method string getOrganizationName(Lasso::Server server, string idp)
|
|
|
|
# Return name of organization picked up from metadata
|
|
|
|
#@param server Lasso::Server object
|
|
|
|
#@param string entityID
|
|
|
|
#@return string organization name
|
|
|
|
sub getOrganizationName {
|
2010-02-08 11:06:21 +01:00
|
|
|
my ( $self, $server, $idp ) = splice @_;
|
|
|
|
my ( $provider, $node );
|
2010-02-05 18:18:09 +01:00
|
|
|
|
|
|
|
# Get provider from server
|
|
|
|
eval { $provider = Lasso::Server::get_provider( $server, $idp ); };
|
2010-02-09 21:49:23 +01:00
|
|
|
|
2010-02-08 18:24:45 +01:00
|
|
|
if ($@) {
|
2010-02-08 11:16:28 +01:00
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
2010-02-05 18:18:09 +01:00
|
|
|
|
|
|
|
# Get organization node
|
|
|
|
eval { $node = Lasso::Provider::get_organization($provider); };
|
2010-02-09 21:49:23 +01:00
|
|
|
|
2010-02-08 18:24:45 +01:00
|
|
|
if ($@) {
|
2010-02-08 11:16:28 +01:00
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
2010-02-05 18:18:09 +01:00
|
|
|
|
2010-02-12 11:53:43 +01:00
|
|
|
# Return if node is empty
|
|
|
|
return unless $node;
|
|
|
|
|
2010-02-05 18:18:09 +01:00
|
|
|
# Extract organization name
|
|
|
|
my $xs = XML::Simple->new();
|
|
|
|
my $data = $xs->XMLin($node);
|
|
|
|
return $data->{OrganizationName}->{content};
|
|
|
|
}
|
|
|
|
|
2010-04-22 19:01:37 +02:00
|
|
|
## @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 {
|
2010-04-28 21:57:16 +02:00
|
|
|
my $self = shift;
|
2010-04-22 19:01:37 +02:00
|
|
|
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 {
|
2010-04-28 21:57:16 +02:00
|
|
|
my $self = shift;
|
2010-04-22 19:01:37 +02:00
|
|
|
my $logout = shift;
|
|
|
|
|
|
|
|
eval { Lasso::Logout::reset_providerID_index($logout); };
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-01 18:32:51 +02:00
|
|
|
## @method Lasso::Login createAuthnRequest(Lasso::Server server, string idp, int method, boolean forceAuthn, boolean isPassive, string nameIDFormat, boolean allowProxiedAuthn, boolean signSSOMessage, string requestedAuthnContext)
|
2010-02-04 17:02:02 +01:00
|
|
|
# Create authentication request for selected IDP
|
2010-02-26 10:12:18 +01:00
|
|
|
# @param server Lasso::Server object
|
|
|
|
# @param entityID IDP entityID
|
|
|
|
# @param method HTTP method
|
2010-03-05 09:54:01 +01:00
|
|
|
# @param forceAuthn force authentication on IDP
|
2010-04-01 16:40:29 +02:00
|
|
|
# @param isPassive require passive authentication
|
2010-03-05 10:28:28 +01:00
|
|
|
# @param nameIDFormat SAML2 NameIDFormat
|
2010-03-24 13:33:45 +01:00
|
|
|
# @param allowProxiedAuthn allow proxy on IDP
|
2010-04-01 16:18:37 +02:00
|
|
|
# @param signSSOMessage sign request
|
2010-04-01 18:32:51 +02:00
|
|
|
# @param requestedAuthnContext authentication context
|
2010-02-04 17:02:02 +01:00
|
|
|
# @return Lasso::Login object
|
|
|
|
sub createAuthnRequest {
|
2010-04-01 16:40:29 +02:00
|
|
|
my (
|
|
|
|
$self, $server, $idp,
|
|
|
|
$method, $forceAuthn, $isPassive,
|
2010-04-01 18:32:51 +02:00
|
|
|
$nameIDFormat, $allowProxiedAuthn, $signSSOMessage,
|
|
|
|
$requestedAuthnContext
|
2010-04-01 16:40:29 +02:00
|
|
|
) = splice @_;
|
2010-06-28 17:00:14 +02:00
|
|
|
my $proxyCount;
|
|
|
|
my $proxyRequestedAuthnContext;
|
2010-02-04 17:02:02 +01:00
|
|
|
|
|
|
|
# Create Lasso Login
|
|
|
|
my $login = $self->createLogin($server);
|
|
|
|
|
|
|
|
unless ($login) {
|
|
|
|
$self->lmLog( 'Unable to create Lasso login', 'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Init authentication request
|
|
|
|
unless ( $self->initAuthnRequest( $login, $idp, $method ) ) {
|
|
|
|
$self->lmLog( "Could not initiate authentication request on $idp",
|
|
|
|
'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-25 12:39:55 +01:00
|
|
|
# Set RelayState
|
|
|
|
my $infos;
|
2010-04-30 16:55:40 +02:00
|
|
|
foreach (qw /urldc/) {
|
2010-02-25 12:39:55 +01:00
|
|
|
$infos->{$_} = $self->{$_} if $self->{$_};
|
2010-02-11 13:39:42 +01:00
|
|
|
}
|
2010-02-25 12:39:55 +01:00
|
|
|
my $relaystate = $self->storeRelayState($infos);
|
2010-02-12 11:53:43 +01:00
|
|
|
$login->msg_relayState($relaystate);
|
|
|
|
$self->lmLog( "Set $relaystate in RelayState", 'debug' );
|
2010-02-11 13:39:42 +01:00
|
|
|
|
2010-02-10 18:18:46 +01:00
|
|
|
# Customize request
|
|
|
|
my $request = $login->request();
|
2010-03-05 10:28:28 +01:00
|
|
|
|
2010-06-28 17:00:14 +02:00
|
|
|
# Maybe we are in IDP proxy mode (SAML request received on IDP side)
|
|
|
|
# In this case:
|
|
|
|
# * Check proxy conditions
|
|
|
|
# * Forward some authn constraints
|
2010-07-02 13:29:00 +02:00
|
|
|
if ( $self->{_proxiedSamlRequest} ) {
|
2010-06-28 17:00:14 +02:00
|
|
|
|
|
|
|
$self->lmLog( "IDP Proxy mode detected", 'debug' );
|
|
|
|
|
|
|
|
# Get ProxyCount value
|
2010-07-02 13:29:00 +02:00
|
|
|
eval {
|
|
|
|
$proxyCount = $self->{_proxiedSamlRequest}->Scoping()->ProxyCount();
|
|
|
|
};
|
2010-06-28 17:00:14 +02:00
|
|
|
|
|
|
|
# Deny request if ProxyCount eq 0
|
|
|
|
if ( defined $proxyCount ) {
|
|
|
|
|
|
|
|
$self->lmLog( "Found proxyCount $proxyCount in proxied request",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
if ( $proxyCount eq 0 ) {
|
|
|
|
$self->lmLog( "SAML request cannot be proxied (ProxyCount 0)",
|
|
|
|
'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
# Decrease ProxyCount
|
2010-07-02 13:29:00 +02:00
|
|
|
my $scoping = $self->{_proxiedSamlRequest}->Scoping();
|
2010-06-28 17:00:14 +02:00
|
|
|
$scoping->ProxyCount( $proxyCount-- );
|
|
|
|
eval { $request->Scoping($scoping); };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# isPassive
|
2010-07-02 13:29:00 +02:00
|
|
|
eval { $isPassive = $self->{_proxiedSamlRequest}->IsPassive(); };
|
2010-06-28 17:00:14 +02:00
|
|
|
|
|
|
|
# forceAuthn
|
2010-07-02 13:29:00 +02:00
|
|
|
eval { $forceAuthn = $self->{_proxiedSamlRequest}->ForceAuthn(); };
|
2010-06-28 17:00:14 +02:00
|
|
|
|
|
|
|
# requestedAuthnContext
|
|
|
|
eval {
|
|
|
|
$proxyRequestedAuthnContext =
|
2010-07-02 13:29:00 +02:00
|
|
|
$self->{_proxiedSamlRequest}->RequestedAuthnContext();
|
2010-06-28 17:00:14 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2010-03-05 10:28:28 +01:00
|
|
|
# NameIDFormat
|
|
|
|
if ($nameIDFormat) {
|
|
|
|
$self->lmLog( "Use NameIDFormat $nameIDFormat", 'debug' );
|
|
|
|
$request->NameIDPolicy()->Format($nameIDFormat);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Always allow NameID creation
|
2010-02-11 13:39:42 +01:00
|
|
|
$request->NameIDPolicy()->AllowCreate(1);
|
2010-03-05 10:28:28 +01:00
|
|
|
|
|
|
|
# Force authentication
|
2010-03-05 09:54:01 +01:00
|
|
|
if ($forceAuthn) {
|
|
|
|
$self->lmLog( "Force authentication on IDP", 'debug' );
|
|
|
|
$request->ForceAuthn(1);
|
|
|
|
}
|
2010-02-10 18:18:46 +01:00
|
|
|
|
2010-04-01 16:40:29 +02:00
|
|
|
# Passive authentication
|
|
|
|
if ($isPassive) {
|
|
|
|
$self->lmLog( "Passive authentication on IDP", 'debug' );
|
|
|
|
$request->IsPassive(1);
|
|
|
|
}
|
|
|
|
|
2010-03-24 13:33:45 +01:00
|
|
|
# Allow proxy
|
|
|
|
unless ($allowProxiedAuthn) {
|
|
|
|
$self->lmLog( "Do not allow this request to be proxied", 'debug' );
|
|
|
|
eval {
|
|
|
|
my $proxyRestriction = Lasso::Saml2ProxyRestriction->new();
|
|
|
|
$proxyRestriction->Audience($idp);
|
|
|
|
$proxyRestriction->Count(0);
|
|
|
|
my $conditions = $request->Conditions()
|
|
|
|
|| Lasso::Saml2Conditions->new();
|
|
|
|
$conditions->ProxyRestriction($proxyRestriction);
|
|
|
|
$request->Conditions($conditions);
|
|
|
|
};
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-01 11:55:33 +02:00
|
|
|
# Signature
|
2010-07-01 18:05:57 +02:00
|
|
|
if ( $signSSOMessage == 0 ) {
|
|
|
|
$self->lmLog( "SSO request will not be signed", 'debug' );
|
|
|
|
$self->disableSignature($login);
|
|
|
|
}
|
|
|
|
elsif ( $signSSOMessage == 1 ) {
|
|
|
|
$self->lmLog( "SSO request will be signed", 'debug' );
|
|
|
|
$self->forceSignature($login);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog( "SSO request signature according to metadata", 'debug' );
|
2010-04-01 11:55:33 +02:00
|
|
|
}
|
|
|
|
|
2010-04-01 18:32:51 +02:00
|
|
|
# Requested authentication context
|
2010-06-28 17:00:14 +02:00
|
|
|
if ($proxyRequestedAuthnContext) {
|
|
|
|
$self->lmLog( "Use RequestedAuthnContext from proxied request",
|
|
|
|
'debug' );
|
|
|
|
$request->RequestedAuthnContext($proxyRequestedAuthnContext);
|
|
|
|
}
|
|
|
|
elsif ($requestedAuthnContext) {
|
2010-04-01 18:32:51 +02:00
|
|
|
$self->lmLog( "Request $requestedAuthnContext context", 'debug' );
|
|
|
|
eval {
|
|
|
|
my $context = Lasso::Samlp2RequestedAuthnContext->new();
|
|
|
|
$context->AuthnContextClassRef($requestedAuthnContext);
|
2010-05-12 17:14:07 +02:00
|
|
|
$context->Comparison("minimum");
|
2010-04-01 18:32:51 +02:00
|
|
|
$request->RequestedAuthnContext($context);
|
|
|
|
};
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-04 17:02:02 +01:00
|
|
|
# Build authentication request
|
2010-07-02 10:14:26 +02:00
|
|
|
unless ( $self->buildAuthnRequestMsg($login) ) {
|
|
|
|
$self->lmLog( "Could not build authentication request on $idp",
|
|
|
|
'error' );
|
|
|
|
return;
|
|
|
|
}
|
2010-07-01 11:48:50 +02:00
|
|
|
|
|
|
|
# Artifact
|
|
|
|
if ( $method == $self->getHttpMethod("artifact-get")
|
|
|
|
or $method == $self->getHttpMethod("artifact-post") )
|
|
|
|
{
|
|
|
|
|
|
|
|
# Get artifact ID and Content, and store them
|
|
|
|
my $artifact_id = $login->get_artifact;
|
|
|
|
my $artifact_message = $login->get_artifact_message;
|
|
|
|
|
|
|
|
$self->storeArtifact( $artifact_id, $artifact_message );
|
|
|
|
}
|
2010-02-04 17:02:02 +01:00
|
|
|
return $login;
|
|
|
|
}
|
|
|
|
|
2010-02-17 18:37:38 +01:00
|
|
|
## @method Lasso::Login createLogin(Lasso::Server server, string dump)
|
2010-02-04 17:02:02 +01:00
|
|
|
# Create Lasso::Login object
|
2010-02-17 18:37:38 +01:00
|
|
|
# @param server Lasso::Server object
|
|
|
|
# @param dump optional XML dump
|
2010-02-04 17:02:02 +01:00
|
|
|
# @return Lasso::Login object
|
|
|
|
sub createLogin {
|
2010-02-17 18:37:38 +01:00
|
|
|
my ( $self, $server, $dump ) = splice @_;
|
2010-02-04 17:02:02 +01:00
|
|
|
my $login;
|
|
|
|
|
2010-02-17 18:37:38 +01:00
|
|
|
if ($dump) {
|
|
|
|
eval { $login = Lasso::Login::new_from_dump( $server, $dump ); };
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
eval { $login = Lasso::Login->new($server); };
|
|
|
|
}
|
2010-02-04 17:02:02 +01:00
|
|
|
|
2010-02-09 21:49:23 +01:00
|
|
|
if ($@) {
|
2010-02-12 11:53:43 +01:00
|
|
|
$self->checkLassoError($@);
|
2010-02-09 21:49:23 +01:00
|
|
|
return;
|
|
|
|
}
|
2010-02-04 17:02:02 +01:00
|
|
|
|
|
|
|
return $login;
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean initAuthnRequest(Lasso::Login login, string idp, int method)
|
|
|
|
# Init authentication request
|
|
|
|
# @param Lasso::Login login
|
|
|
|
# @param string entityID
|
|
|
|
# @param int HTTP method
|
|
|
|
# @return boolean result
|
|
|
|
sub initAuthnRequest {
|
2010-02-08 11:06:21 +01:00
|
|
|
my ( $self, $login, $idp, $method ) = splice @_;
|
2010-02-04 17:02:02 +01:00
|
|
|
|
|
|
|
eval { Lasso::Login::init_authn_request( $login, $idp, $method ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean buildAuthnRequestMsg(Lasso::Login login)
|
|
|
|
# Build authentication request message
|
|
|
|
# @param Lasso::Login login
|
|
|
|
# @return boolean result
|
|
|
|
sub buildAuthnRequestMsg {
|
2010-02-08 11:06:21 +01:00
|
|
|
my ( $self, $login ) = splice @_;
|
2010-02-04 17:02:02 +01:00
|
|
|
|
|
|
|
eval { Lasso::Login::build_authn_request_msg($login); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
2010-02-01 18:07:40 +01:00
|
|
|
|
2010-03-26 14:56:37 +01:00
|
|
|
## @method boolean processAuthnRequestMsg(Lasso::Login login, string request)
|
|
|
|
# Process authentication request message
|
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @param response SAML request
|
|
|
|
# @return result
|
|
|
|
sub processAuthnRequestMsg {
|
|
|
|
my ( $self, $login, $request ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Login::process_authn_request_msg( $login, $request ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
## @method boolean validateRequestMsg(Lasso::Login login, boolean auth, boolean consent)
|
|
|
|
# Validate request message
|
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @param auth is user authenticated?
|
|
|
|
# @param consent is consent obtained?
|
|
|
|
# @return result
|
|
|
|
sub validateRequestMsg {
|
|
|
|
my ( $self, $login, $auth, $consent ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Login::validate_request_msg( $login, $auth, $consent ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-07 17:14:17 +02:00
|
|
|
## @method boolean buildAuthnResponseMsg(Lasso::Login login)
|
|
|
|
# Build authentication response message
|
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @return boolean result
|
|
|
|
sub buildAuthnResponseMsg {
|
|
|
|
my ( $self, $login ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Login::build_authn_response_msg($login); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean buildArtifactMsg(Lasso::Login login, int method)
|
|
|
|
# Build artifact message
|
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @param method HTTP method
|
|
|
|
# @return boolean result
|
|
|
|
sub buildArtifactMsg {
|
|
|
|
my ( $self, $login, $method ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Login::build_artifact_msg( $login, $method ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-07 18:37:23 +02:00
|
|
|
## @method boolean buildAssertion(Lasso::Login login, string authn_context)
|
|
|
|
# Build assertion
|
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @param authn_context SAML2 authentication context
|
|
|
|
# @return boolean result
|
|
|
|
sub buildAssertion {
|
|
|
|
my ( $self, $login, $authn_context ) = splice @_;
|
|
|
|
|
2010-04-08 11:39:53 +02:00
|
|
|
# Dates
|
2010-04-16 15:38:43 +02:00
|
|
|
my $time = $self->{sessionInfo}->{_utime} || time();
|
2010-04-08 11:39:53 +02:00
|
|
|
my $timeout = $time + $self->{timeout};
|
|
|
|
my $authenticationInstant = $self->timestamp2samldate($time);
|
|
|
|
my $reauthenticateOnOrAfter = $self->timestamp2samldate($timeout);
|
|
|
|
my $notBefore = $authenticationInstant;
|
|
|
|
my $notOnOrAfter = $reauthenticateOnOrAfter;
|
2010-04-07 18:37:23 +02:00
|
|
|
|
|
|
|
eval {
|
2010-04-08 11:39:53 +02:00
|
|
|
Lasso::Login::build_assertion( $login, $authn_context,
|
|
|
|
$authenticationInstant, $reauthenticateOnOrAfter, $notBefore,
|
|
|
|
$notOnOrAfter );
|
2010-04-07 18:37:23 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-02-08 18:24:45 +01:00
|
|
|
## @method boolean processAuthnResponseMsg(Lasso::Login login, string response)
|
|
|
|
# Process authentication response message
|
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @param response SAML response
|
|
|
|
# @return result
|
|
|
|
sub processAuthnResponseMsg {
|
|
|
|
my ( $self, $login, $response ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Login::process_authn_response_msg( $login, $response ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-02-09 10:02:39 +01:00
|
|
|
## @method Lasso::Saml2NameID getNameIdentifer(Lasso::Profile profile)
|
|
|
|
# Get NameID from Lasso Profile
|
|
|
|
# @param profile Lasso::Profile object
|
|
|
|
# @return result or NULL if error
|
|
|
|
sub getNameIdentifier {
|
|
|
|
my ( $self, $profile ) = splice @_;
|
|
|
|
my $nameid;
|
|
|
|
|
|
|
|
eval { $nameid = Lasso::Profile::get_nameIdentifier($profile); };
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $nameid;
|
|
|
|
}
|
|
|
|
|
2010-02-11 13:39:42 +01:00
|
|
|
## @method Lasso::Identity createIdentity(string dump)
|
|
|
|
# Create Lasso::Identity object
|
|
|
|
# @param dump optional Identity dump
|
|
|
|
# @return Lasso::Identity object
|
|
|
|
sub createIdentity {
|
|
|
|
my ( $self, $dump ) = splice @_;
|
|
|
|
my $identity;
|
|
|
|
|
|
|
|
if ($dump) {
|
|
|
|
eval { $identity = Lasso::Identity::new_from_dump($dump); };
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
eval { $identity = Lasso::Identity->new(); };
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $identity;
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method Lasso::Session createSession(string dump)
|
|
|
|
# Create Lasso::Session object
|
|
|
|
# @param dump optional Session dump
|
|
|
|
# @return Lasso::Session object
|
|
|
|
sub createSession {
|
|
|
|
my ( $self, $dump ) = splice @_;
|
|
|
|
my $session;
|
|
|
|
|
|
|
|
if ($dump) {
|
|
|
|
eval { $session = Lasso::Session::new_from_dump($dump); };
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
eval { $session = Lasso::Session->new(); };
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $session;
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean acceptSSO(Lasso::Login login)
|
|
|
|
# Accept SSO from IDP
|
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @return result
|
|
|
|
sub acceptSSO {
|
|
|
|
my ( $self, $login ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Login::accept_sso($login); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-02-25 12:39:55 +01:00
|
|
|
## @method string storeRelayState(hashref infos)
|
|
|
|
# Store information in relayState database and return
|
|
|
|
# corresponding session_id
|
|
|
|
# @param infos HASH reference of information
|
|
|
|
sub storeRelayState {
|
|
|
|
my ( $self, $infos ) = splice @_;
|
|
|
|
|
|
|
|
# Create relaystate session
|
2010-06-28 18:22:07 +02:00
|
|
|
my $samlSessionInfo = $self->getSamlSession();
|
|
|
|
|
|
|
|
return unless $samlSessionInfo;
|
2010-02-25 12:39:55 +01:00
|
|
|
|
|
|
|
# Session type
|
2010-06-28 18:22:07 +02:00
|
|
|
$samlSessionInfo->{_type} = "relaystate";
|
2010-02-25 12:39:55 +01:00
|
|
|
|
2010-02-28 20:07:02 +01:00
|
|
|
# UNIX time
|
2010-06-28 18:22:07 +02:00
|
|
|
$samlSessionInfo->{_utime} = time();
|
2010-02-28 20:07:02 +01:00
|
|
|
|
2010-02-25 12:39:55 +01:00
|
|
|
# Store infos in relaystate session
|
|
|
|
foreach ( keys %$infos ) {
|
2010-06-28 18:22:07 +02:00
|
|
|
$samlSessionInfo->{$_} = $infos->{$_};
|
2010-02-25 12:39:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# Session ID
|
2010-06-28 18:22:07 +02:00
|
|
|
my $relaystate_id = $samlSessionInfo->{_session_id};
|
2010-02-25 12:39:55 +01:00
|
|
|
|
|
|
|
# Close session
|
2010-06-28 18:22:07 +02:00
|
|
|
untie %$samlSessionInfo;
|
2010-02-25 12:39:55 +01:00
|
|
|
|
|
|
|
# Return session ID
|
|
|
|
return $relaystate_id;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean extractRelayState(string relaystate)
|
2010-02-12 11:53:43 +01:00
|
|
|
# Extract RelayState information into $self
|
2010-02-25 12:39:55 +01:00
|
|
|
# @param relayState relayState value
|
|
|
|
# @return result
|
2010-02-12 11:53:43 +01:00
|
|
|
sub extractRelayState {
|
2010-02-25 12:39:55 +01:00
|
|
|
my ( $self, $relaystate ) = splice @_;
|
2010-02-12 11:53:43 +01:00
|
|
|
|
|
|
|
return 0 unless $relaystate;
|
|
|
|
|
2010-02-25 12:39:55 +01:00
|
|
|
# Open relaystate session
|
2010-06-28 18:22:07 +02:00
|
|
|
my $samlSessionInfo = $self->getSamlSession($relaystate);
|
|
|
|
|
|
|
|
return 0 unless $samlSessionInfo;
|
2010-02-12 11:53:43 +01:00
|
|
|
|
|
|
|
# Push values in $self
|
2010-06-28 18:22:07 +02:00
|
|
|
foreach ( keys %$samlSessionInfo ) {
|
2010-02-28 20:07:02 +01:00
|
|
|
next if $_ =~ /(type|_session_id|_utime)/;
|
2010-06-28 18:22:07 +02:00
|
|
|
$self->{$_} = $samlSessionInfo->{$_};
|
2010-02-12 11:53:43 +01:00
|
|
|
}
|
|
|
|
|
2010-06-28 18:22:07 +02:00
|
|
|
untie %$samlSessionInfo;
|
|
|
|
|
2010-02-12 11:53:43 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-02-12 15:26:45 +01:00
|
|
|
## @method Lasso::Node getAssertion(Lasso::Login login)
|
|
|
|
# Get assertion in Lasso::Login object
|
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @return assertion Lasso::Node object
|
|
|
|
sub getAssertion {
|
|
|
|
my ( $self, $login ) = splice @_;
|
|
|
|
my $assertion;
|
|
|
|
|
|
|
|
eval { $assertion = Lasso::Login::get_assertion($login); };
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $assertion;
|
|
|
|
}
|
|
|
|
|
2010-05-28 17:31:20 +02:00
|
|
|
## @method string getAttributeValue(string name, string format, string friendly_name, array_ref attributes, boolean force_utf8)
|
2010-02-12 15:26:45 +01:00
|
|
|
# Get SAML attribute value corresponding to name, format and friendly_name
|
2010-04-15 13:15:36 +02:00
|
|
|
# Multivaluated values are separated by multiValuesSeparator
|
2010-05-28 17:31:20 +02:00
|
|
|
# If force_utf8 flag is set, value is encoded in UTF-8
|
2010-02-12 15:26:45 +01:00
|
|
|
# @param name SAML attribute name
|
|
|
|
# @param format optional SAML attribute format
|
|
|
|
# @param friendly_name optional SAML attribute friendly name
|
2010-05-28 17:31:20 +02:00
|
|
|
# @param force_utf8 optional flag to force value in UTF-8
|
2010-02-12 15:26:45 +01:00
|
|
|
# @return attribute value
|
|
|
|
sub getAttributeValue {
|
2010-05-28 17:31:20 +02:00
|
|
|
my ( $self, $name, $format, $friendly_name, $attributes, $force_utf8 ) =
|
|
|
|
splice @_;
|
2010-02-12 15:26:45 +01:00
|
|
|
my $value;
|
|
|
|
|
|
|
|
# Loop on attributes
|
|
|
|
foreach (@$attributes) {
|
|
|
|
my $attr_name = $_->Name();
|
|
|
|
my $attr_format = $_->NameFormat();
|
|
|
|
my $attr_fname = $_->FriendlyName();
|
|
|
|
|
|
|
|
# Skip if name does not correspond to attribute name
|
|
|
|
next if ( $name ne $attr_name );
|
|
|
|
|
|
|
|
# Verify format and friendly name if given
|
|
|
|
next if ( $format and $format ne $attr_format );
|
|
|
|
next if ( $friendly_name and $friendly_name ne $attr_fname );
|
|
|
|
|
|
|
|
# Attribute is found, return its content
|
|
|
|
my @attr_values = $_->AttributeValue();
|
|
|
|
|
|
|
|
foreach (@attr_values) {
|
|
|
|
my $xs = XML::Simple->new();
|
|
|
|
my $data = $xs->XMLin( $_->dump() );
|
|
|
|
my $content = $data->{content};
|
2010-04-15 13:15:36 +02:00
|
|
|
$value .= $content . $self->{multiValuesSeparator} if $content;
|
2010-02-12 15:26:45 +01:00
|
|
|
}
|
2010-04-15 13:15:36 +02:00
|
|
|
$value =~ s/\Q$self->{multiValuesSeparator}\E$//;
|
2010-04-28 16:56:36 +02:00
|
|
|
|
2010-05-28 17:31:20 +02:00
|
|
|
# Encode UTF-8 if force_utf8 flag
|
|
|
|
$value = encode( "utf8", $value ) if $force_utf8;
|
2010-04-28 16:56:36 +02:00
|
|
|
|
2010-02-12 15:26:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
2010-02-15 18:03:07 +01:00
|
|
|
## @method boolean validateConditions(Lasso::Saml2::Assertion assertion, string entityID)
|
|
|
|
# Validate conditions
|
|
|
|
# @param assertion SAML2 assertion
|
|
|
|
# @param entityID relaying party entity ID
|
|
|
|
# @return result
|
|
|
|
sub validateConditions {
|
|
|
|
my ( $self, $assertion, $entityID ) = splice @_;
|
2010-03-01 10:42:25 +01:00
|
|
|
my $tolerance = 10;
|
2010-02-15 18:03:07 +01:00
|
|
|
my $status;
|
|
|
|
|
2010-03-01 10:42:25 +01:00
|
|
|
# Time
|
2010-02-15 18:03:07 +01:00
|
|
|
eval {
|
|
|
|
$status =
|
2010-03-01 10:42:25 +01:00
|
|
|
Lasso::Saml2Assertion::validate_time_checks( $assertion, $tolerance );
|
2010-02-15 18:03:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unless ( $status eq Lasso::Constants::SAML2_ASSERTION_VALID ) {
|
2010-03-01 10:42:25 +01:00
|
|
|
$self->lmLog( "Time conditions validations result: $status", 'error' );
|
2010-02-15 18:03:07 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-03-01 10:42:25 +01:00
|
|
|
$self->lmLog( "Time conditions validated", 'debug' );
|
|
|
|
|
|
|
|
# Audience
|
|
|
|
eval {
|
|
|
|
$status =
|
|
|
|
Lasso::Saml2Assertion::validate_audience( $assertion, $entityID );
|
|
|
|
};
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unless ( $status eq Lasso::Constants::SAML2_ASSERTION_VALID ) {
|
|
|
|
$self->lmLog( "Audience conditions validations result: $status",
|
|
|
|
'error' );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Audience conditions validated", 'debug' );
|
|
|
|
|
2010-02-15 18:03:07 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-04-01 16:18:37 +02:00
|
|
|
## @method Lasso::Logout createLogoutRequest(Lasso::Server server, string session_dump, int method, boolean signSLOMessage)
|
2010-02-17 16:13:00 +01:00
|
|
|
# Create logout request for selected entity
|
|
|
|
# @param server Lasso::Server object
|
2010-02-17 18:37:38 +01:00
|
|
|
# @param session_dump Lasso::Session dump
|
2010-02-26 10:12:18 +01:00
|
|
|
# @param method HTTP method
|
2010-04-01 16:18:37 +02:00
|
|
|
# @param signSLOMessage sign request
|
2010-02-17 16:13:00 +01:00
|
|
|
# @return Lasso::Login object
|
|
|
|
sub createLogoutRequest {
|
2010-04-01 16:18:37 +02:00
|
|
|
my ( $self, $server, $session_dump, $method, $signSLOMessage ) = splice @_;
|
2010-02-17 18:37:38 +01:00
|
|
|
my $session;
|
2010-02-17 16:13:00 +01:00
|
|
|
|
|
|
|
# Create Lasso Logout
|
|
|
|
my $logout = $self->createLogout($server);
|
|
|
|
|
2010-02-17 18:37:38 +01:00
|
|
|
unless ( $self->setSessionFromDump( $logout, $session_dump ) ) {
|
2010-02-28 20:07:02 +01:00
|
|
|
$self->lmLog( "Could not fill Lasso::Logout with session dump",
|
|
|
|
'error' );
|
2010-02-17 18:37:38 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-17 16:13:00 +01:00
|
|
|
# Init logout request
|
2010-02-18 10:58:59 +01:00
|
|
|
unless ( $self->initLogoutRequest( $logout, undef, $method ) ) {
|
2010-02-17 18:37:38 +01:00
|
|
|
$self->lmLog( "Could not initiate logout request", 'error' );
|
2010-02-17 16:13:00 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-01 10:19:28 +01:00
|
|
|
# Set RelayState
|
|
|
|
my $infos;
|
|
|
|
foreach (qw /urldc/) {
|
|
|
|
$infos->{$_} = $self->{$_} if $self->{$_};
|
|
|
|
}
|
|
|
|
my $relaystate = $self->storeRelayState($infos);
|
|
|
|
$logout->msg_relayState($relaystate);
|
|
|
|
$self->lmLog( "Set $relaystate in RelayState", 'debug' );
|
|
|
|
|
2010-04-01 16:18:37 +02:00
|
|
|
# Signature
|
2010-07-01 18:05:57 +02:00
|
|
|
if ( $signSLOMessage == 0 ) {
|
|
|
|
$self->lmLog( "SLO request will not be signed", 'debug' );
|
|
|
|
$self->disableSignature($logout);
|
|
|
|
}
|
|
|
|
elsif ( $signSLOMessage == 1 ) {
|
|
|
|
$self->lmLog( "SLO request will be signed", 'debug' );
|
|
|
|
$self->forceSignature($logout);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog( "SLO request signature according to metadata", 'debug' );
|
2010-04-01 16:18:37 +02:00
|
|
|
}
|
|
|
|
|
2010-02-17 16:13:00 +01:00
|
|
|
# Build logout request
|
|
|
|
unless ( $self->buildLogoutRequestMsg($logout) ) {
|
2010-02-17 18:37:38 +01:00
|
|
|
$self->lmLog( "Could not build logout request", 'error' );
|
2010-02-17 16:13:00 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $logout;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-06-11 12:17:43 +02:00
|
|
|
## @method Lasso::Logout createLogout(Lasso::Server server, string dump)
|
2010-02-17 16:13:00 +01:00
|
|
|
# Create Lasso::Logout object
|
|
|
|
# @param server Lasso::Server object
|
2010-06-11 12:17:43 +02:00
|
|
|
# @param dump optional XML dump
|
2010-02-17 16:13:00 +01:00
|
|
|
# @return Lasso::Logout object
|
|
|
|
sub createLogout {
|
2010-06-11 12:17:43 +02:00
|
|
|
my ( $self, $server, $dump ) = splice @_;
|
2010-02-17 16:13:00 +01:00
|
|
|
my $logout;
|
|
|
|
|
2010-06-11 12:17:43 +02:00
|
|
|
if ($dump) {
|
|
|
|
eval { $logout = Lasso::Logout::new_from_dump( $server, $dump ); };
|
|
|
|
}
|
|
|
|
else {
|
2010-06-21 17:29:59 +02:00
|
|
|
eval { $logout = Lasso::Logout->new($server); };
|
2010-06-11 12:17:43 +02:00
|
|
|
}
|
2010-02-17 16:13:00 +01:00
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $logout;
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean initLogoutRequest(Lasso::Logout logout, string entityID, int method)
|
|
|
|
# Init logout request
|
|
|
|
# @param logout Lasso::Logout object
|
|
|
|
# @param entityID
|
|
|
|
# @param HTTP method
|
|
|
|
# @return result
|
|
|
|
sub initLogoutRequest {
|
|
|
|
my ( $self, $logout, $entityID, $method ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Logout::init_request( $logout, $entityID, $method ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean buildLogoutRequestMsg(Lasso::Logout logout)
|
|
|
|
# Build logout request message
|
|
|
|
# @param logout Lasso::Logout object
|
|
|
|
# @return result
|
|
|
|
sub buildLogoutRequestMsg {
|
|
|
|
my ( $self, $logout ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Logout::build_request_msg($logout); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-12 15:23:22 +02:00
|
|
|
## @method boolean setSessionFromDump(Lasso::Profile profile, string dump)
|
2010-02-17 18:37:38 +01:00
|
|
|
# Set session from dump in Lasso::Profile object
|
|
|
|
# @param profile Lasso::Profile object
|
|
|
|
# @param dump Lasso::Session XML dump
|
|
|
|
# @return result
|
|
|
|
sub setSessionFromDump {
|
|
|
|
my ( $self, $profile, $dump ) = splice @_;
|
|
|
|
|
2010-07-02 16:17:01 +02:00
|
|
|
$self->lmLog( "Loading Session dump: $dump", 'debug' );
|
|
|
|
|
2010-02-17 18:37:38 +01:00
|
|
|
eval { Lasso::Profile::set_session_from_dump( $profile, $dump ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-12 15:23:22 +02:00
|
|
|
## @method boolean setIdentityFromDump(Lasso::Profile profile, string dump)
|
|
|
|
# Set identity from dump in Lasso::Profile object
|
|
|
|
# @param profile Lasso::Profile object
|
|
|
|
# @param dump Lasso::Identity XML dump
|
|
|
|
# @return result
|
|
|
|
sub setIdentityFromDump {
|
|
|
|
my ( $self, $profile, $dump ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Profile::set_identity_from_dump( $profile, $dump ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-02-18 18:22:04 +01:00
|
|
|
## @method string getMetaDataURL(string key, int index)
|
2010-02-18 10:58:59 +01:00
|
|
|
# Get URL stored in a service metadata configuration key
|
2010-08-18 11:49:55 +02:00
|
|
|
# Replace #PORTAL# macro
|
2010-02-18 10:58:59 +01:00
|
|
|
# @param key Metadata configuration key
|
2010-02-18 18:22:04 +01:00
|
|
|
# @param index field index containing URL
|
2010-02-18 10:58:59 +01:00
|
|
|
# @return url
|
|
|
|
sub getMetaDataURL {
|
2010-02-18 18:22:04 +01:00
|
|
|
my ( $self, $key, $index ) = splice @_;
|
|
|
|
$index = 3 unless defined $index;
|
2010-02-18 10:58:59 +01:00
|
|
|
|
|
|
|
return unless defined $self->{$key};
|
|
|
|
|
2010-08-18 11:49:55 +02:00
|
|
|
my $url = ( split( /;/, $self->{$key} ) )[$index];
|
|
|
|
|
|
|
|
# Get portal value
|
|
|
|
my $portal = $self->{portal};
|
|
|
|
$portal =~ s/\/$//;
|
|
|
|
|
|
|
|
# Replace #PORTAL# macro
|
|
|
|
$url =~ s/#PORTAL#/$portal/g;
|
|
|
|
|
|
|
|
# Return URL
|
|
|
|
return $url;
|
2010-02-18 18:22:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean processLogoutResponseMsg(Lasso::Logout logout, string response)
|
|
|
|
# Process logout response message
|
|
|
|
# @param logout Lasso::Logout object
|
|
|
|
# @param response SAML response
|
|
|
|
# @return result
|
|
|
|
sub processLogoutResponseMsg {
|
|
|
|
my ( $self, $logout, $response ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Logout::process_response_msg( $logout, $response ); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean processLogoutRequestMsg(Lasso::Logout logout, string request)
|
|
|
|
# Process logout request message
|
|
|
|
# @param logout Lasso::Logout object
|
|
|
|
# @param request SAML request
|
|
|
|
# @return result
|
|
|
|
sub processLogoutRequestMsg {
|
|
|
|
my ( $self, $logout, $request ) = splice @_;
|
|
|
|
|
2010-06-30 10:05:20 +02:00
|
|
|
# Process the request
|
2010-02-18 18:22:04 +01:00
|
|
|
eval { Lasso::Logout::process_request_msg( $logout, $request ); };
|
|
|
|
|
2010-06-30 10:05:20 +02:00
|
|
|
return 0 unless $self->checkLassoError($@);
|
|
|
|
|
|
|
|
# Check NotOnOrAfter optional attribute
|
|
|
|
my $notOnOrAfter;
|
|
|
|
|
|
|
|
eval { $notOnOrAfter = $logout->request()->NotOnOrAfter(); };
|
|
|
|
|
|
|
|
return 1 if ( $@ or !$notOnOrAfter );
|
|
|
|
|
|
|
|
$self->lmLog( "Found NotOnOrAfter $notOnOrAfter in logout request",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
my $expirationTime = $self->samldate2timestamp($notOnOrAfter);
|
|
|
|
|
|
|
|
return ( time > $expirationTime );
|
2010-02-18 10:58:59 +01:00
|
|
|
}
|
|
|
|
|
2010-02-18 18:42:31 +01:00
|
|
|
## @method boolean validateLogoutRequest(Lasso::Logout logout)
|
|
|
|
# Validate logout request
|
|
|
|
# @param logout Lasso::Logout object
|
|
|
|
# @return result
|
|
|
|
sub validateLogoutRequest {
|
|
|
|
my ( $self, $logout ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Logout::validate_request($logout); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-02-19 12:33:34 +01:00
|
|
|
## @method boolean buildLogoutResponseMsg(Lasso::Logout logout)
|
|
|
|
# Build logout response message
|
|
|
|
# @param Lasso::Logout logout
|
|
|
|
# @return boolean result
|
|
|
|
sub buildLogoutResponseMsg {
|
|
|
|
my ( $self, $logout ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Logout::build_response_msg($logout); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-02-28 20:07:02 +01:00
|
|
|
## @method boolean storeReplayProtection(string samlID)
|
|
|
|
# Store ID of an SAML message in Replay Protection base
|
|
|
|
# @param samlID ID of SAML message
|
2010-04-28 19:16:38 +02:00
|
|
|
# @param samlData Optional data to store
|
2010-02-28 20:07:02 +01:00
|
|
|
# @return result
|
|
|
|
sub storeReplayProtection {
|
2010-04-28 19:16:38 +02:00
|
|
|
my ( $self, $samlID, $samlData ) = splice @_;
|
2010-02-28 20:07:02 +01:00
|
|
|
|
2010-06-28 18:22:07 +02:00
|
|
|
my $samlSessionInfo = $self->getSamlSession();
|
2010-02-28 20:07:02 +01:00
|
|
|
|
2010-06-28 18:22:07 +02:00
|
|
|
return 0 unless $samlSessionInfo;
|
|
|
|
|
|
|
|
$samlSessionInfo->{type} = 'assertion'; # Session type
|
|
|
|
$samlSessionInfo->{_utime} = time(); # Creation time
|
|
|
|
$samlSessionInfo->{ID} = $samlID;
|
2010-02-28 20:07:02 +01:00
|
|
|
|
2010-04-28 19:16:38 +02:00
|
|
|
if ( defined $samlData && $samlData ) {
|
2010-06-28 18:22:07 +02:00
|
|
|
$samlSessionInfo->{data} = $samlData;
|
2010-04-28 19:16:38 +02:00
|
|
|
}
|
|
|
|
|
2010-06-28 18:22:07 +02:00
|
|
|
my $session_id = $samlSessionInfo->{_session_id};
|
2010-02-28 20:07:02 +01:00
|
|
|
|
2010-06-28 18:22:07 +02:00
|
|
|
untie %$samlSessionInfo;
|
2010-02-28 20:07:02 +01:00
|
|
|
|
2010-04-08 18:28:10 +02:00
|
|
|
$self->lmLog( "Keep request ID $samlID in assertion session $session_id",
|
2010-02-28 20:07:02 +01:00
|
|
|
'debug' );
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-02-22 18:12:16 +01:00
|
|
|
## @method boolean replayProtection(string samlID)
|
|
|
|
# Check if SAML message do not correspond to a previously responded message
|
|
|
|
# @param samlID ID of initial SAML message
|
|
|
|
# @return result
|
|
|
|
sub replayProtection {
|
|
|
|
my ( $self, $samlID ) = splice @_;
|
|
|
|
|
|
|
|
unless ($samlID) {
|
|
|
|
$self->lmLog( "Cannot verify replay because no SAML ID given",
|
|
|
|
'error' );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $sessions =
|
2010-04-09 15:27:54 +02:00
|
|
|
$self->{samlStorage}
|
|
|
|
->searchOn( $self->{samlStorageOptions}, "ID", $samlID );
|
2010-02-22 18:12:16 +01:00
|
|
|
|
|
|
|
if ( my @keys = keys %$sessions ) {
|
|
|
|
|
|
|
|
# A session was found
|
|
|
|
foreach (@keys) {
|
|
|
|
my $session = $_;
|
2010-04-29 15:39:26 +02:00
|
|
|
my $result = 1;
|
2010-02-22 18:12:16 +01:00
|
|
|
|
|
|
|
# Delete it
|
2010-06-28 18:22:07 +02:00
|
|
|
my $samlSessionInfo = $self->getSamlSession($_);
|
|
|
|
|
|
|
|
return 0 unless $samlSessionInfo;
|
|
|
|
|
|
|
|
if ( defined $samlSessionInfo->{data} ) {
|
|
|
|
$result = $samlSessionInfo->{data};
|
2010-04-29 15:39:26 +02:00
|
|
|
}
|
2010-06-28 18:22:07 +02:00
|
|
|
eval { tied(%$samlSessionInfo)->delete(); };
|
2010-02-22 18:12:16 +01:00
|
|
|
if ($@) {
|
|
|
|
$self->lmLog(
|
|
|
|
"Unable to delete assertion session $session (Message ID $samlID)",
|
|
|
|
'error'
|
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
$self->lmLog(
|
|
|
|
"Assertion session $session (Message ID $samlID) was deleted",
|
|
|
|
'debug' );
|
2010-04-29 15:39:26 +02:00
|
|
|
return $result;
|
2010-02-22 18:12:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-24 16:24:54 +01:00
|
|
|
## @method string resolveArtifact(Lasso::Profile profile, string artifact, int method)
|
|
|
|
# Resolve artifact to get real SAML message
|
|
|
|
# @param profile Lasso::Profile object
|
|
|
|
# @param artifact Artifact message
|
|
|
|
# @param method HTTP method
|
|
|
|
# @return SAML message
|
|
|
|
sub resolveArtifact {
|
|
|
|
my ( $self, $profile, $artifact, $method ) = splice @_;
|
|
|
|
my $message;
|
|
|
|
|
|
|
|
# LWP User Agent
|
|
|
|
my $ua = new LWP::UserAgent;
|
|
|
|
push @{ $ua->requests_redirectable }, 'POST';
|
|
|
|
|
|
|
|
# Login profile
|
|
|
|
if ( $profile->isa("Lasso::Login") ) {
|
|
|
|
|
|
|
|
# Init request message
|
|
|
|
eval { Lasso::Login::init_request( $profile, $artifact, $method ); };
|
|
|
|
return unless $self->checkLassoError($@);
|
|
|
|
|
|
|
|
# Build request message
|
|
|
|
eval { Lasso::Login::build_request_msg($profile); };
|
|
|
|
return unless $self->checkLassoError($@);
|
|
|
|
|
2010-05-27 14:39:32 +02:00
|
|
|
unless ( $profile->msg_url ) {
|
|
|
|
$self->lmLog( "No artifcat resolution URL found", 'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-24 16:24:54 +01:00
|
|
|
my $request = HTTP::Request->new( 'POST' => $profile->msg_url );
|
|
|
|
$request->content_type('text/xml');
|
|
|
|
$request->content( $profile->msg_body );
|
|
|
|
|
|
|
|
$self->lmLog(
|
|
|
|
"Send message " . $profile->msg_body . " to " . $profile->msg_url,
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
# SOAP call
|
|
|
|
my $soap_answer = $ua->request($request);
|
|
|
|
if ( $soap_answer->code() == "200" ) {
|
|
|
|
$message = $soap_answer->content();
|
|
|
|
$self->lmLog( "Get message $message", 'debug' );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $message;
|
|
|
|
}
|
|
|
|
|
2010-04-12 17:03:54 +02:00
|
|
|
## @method boolean storeArtifact(string id, string message, string session_id)
|
2010-04-08 18:28:10 +02:00
|
|
|
# Store artifact
|
|
|
|
# @param id Artifact ID
|
|
|
|
# @param message Artifact content
|
2010-04-12 17:03:54 +02:00
|
|
|
# @param session_id Session ID
|
2010-04-08 18:28:10 +02:00
|
|
|
# @return result
|
|
|
|
sub storeArtifact {
|
2010-04-12 17:03:54 +02:00
|
|
|
my ( $self, $id, $message, $session_id ) = splice @_;
|
2010-04-08 18:28:10 +02:00
|
|
|
|
2010-06-28 18:22:07 +02:00
|
|
|
my $samlSessionInfo = $self->getSamlSession();
|
2010-04-08 18:28:10 +02:00
|
|
|
|
2010-06-28 18:22:07 +02:00
|
|
|
return 0 unless $samlSessionInfo;
|
2010-04-08 18:28:10 +02:00
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
$samlSessionInfo->{type} = 'artifact'; # Session type
|
|
|
|
$samlSessionInfo->{_utime} = time(); # Creation time
|
|
|
|
$samlSessionInfo->{ID} = $id;
|
|
|
|
$samlSessionInfo->{message} = $message;
|
2010-08-31 16:36:45 +02:00
|
|
|
$samlSessionInfo->{_saml_id} = $session_id if $session_id;
|
2010-04-08 18:28:10 +02:00
|
|
|
|
2010-06-28 18:22:07 +02:00
|
|
|
my $art_session_id = $samlSessionInfo->{_session_id};
|
|
|
|
|
|
|
|
untie %$samlSessionInfo;
|
2010-04-08 18:28:10 +02:00
|
|
|
|
2010-04-12 17:03:54 +02:00
|
|
|
$self->lmLog( "Keep artifact $id in session $art_session_id", 'debug' );
|
2010-04-08 18:28:10 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-04-12 17:03:54 +02:00
|
|
|
## @method hashRef loadArtifact(string id)
|
2010-04-08 18:28:10 +02:00
|
|
|
# Load artifact
|
|
|
|
# @param id Artifact ID
|
2010-04-12 17:03:54 +02:00
|
|
|
# @return Artifact session content
|
2010-04-08 18:28:10 +02:00
|
|
|
sub loadArtifact {
|
|
|
|
my ( $self, $id ) = splice @_;
|
2010-04-12 17:03:54 +02:00
|
|
|
my $art_session;
|
2010-04-08 18:28:10 +02:00
|
|
|
|
|
|
|
unless ($id) {
|
|
|
|
$self->lmLog( "Cannot load artifact because no id given", 'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
my $sessions =
|
2010-04-09 15:27:54 +02:00
|
|
|
$self->{samlStorage}->searchOn( $self->{samlStorageOptions}, "ID", $id );
|
2010-04-08 18:28:10 +02:00
|
|
|
|
|
|
|
if ( my @keys = keys %$sessions ) {
|
|
|
|
|
|
|
|
my $nb_sessions = $#keys + 1;
|
|
|
|
|
|
|
|
$self->lmLog( "Found $nb_sessions sessions for artifact $id", 'debug' );
|
|
|
|
|
|
|
|
# There should only be 1 result
|
|
|
|
return if ( $nb_sessions != 1 );
|
|
|
|
|
|
|
|
my $session_id = shift @keys;
|
|
|
|
my $session = $session_id;
|
|
|
|
|
|
|
|
# Open session
|
2010-06-28 18:22:07 +02:00
|
|
|
my $samlSessionInfo = $self->getSamlSession($session_id);
|
|
|
|
|
|
|
|
return unless $samlSessionInfo;
|
2010-04-08 18:28:10 +02:00
|
|
|
|
2010-04-12 17:03:54 +02:00
|
|
|
# Get session contents
|
2010-06-28 18:22:07 +02:00
|
|
|
foreach ( keys %$samlSessionInfo ) {
|
|
|
|
$art_session->{$_} = $samlSessionInfo->{$_};
|
2010-04-12 17:03:54 +02:00
|
|
|
}
|
2010-04-08 18:28:10 +02:00
|
|
|
|
|
|
|
# Delete session
|
2010-06-28 18:22:07 +02:00
|
|
|
eval { tied(%$samlSessionInfo)->delete(); };
|
2010-04-08 18:28:10 +02:00
|
|
|
if ($@) {
|
|
|
|
$self->lmLog( "Unable to delete artifact session $session (ID $id)",
|
|
|
|
'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$self->lmLog( "Artifact session $session (ID $id) was deleted",
|
|
|
|
'debug' );
|
|
|
|
|
2010-04-12 17:03:54 +02:00
|
|
|
return $art_session;
|
2010-04-08 18:28:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-21 15:44:16 +02:00
|
|
|
## @method string createArtifactResponse(Lasso::Login login)
|
|
|
|
# Create artifact response
|
2010-04-12 11:09:53 +02:00
|
|
|
# @param login Lasso::Login object
|
|
|
|
# @return Artifact response
|
|
|
|
sub createArtifactResponse {
|
2010-05-21 15:44:16 +02:00
|
|
|
my ( $self, $login ) = splice @_;
|
2010-04-12 11:09:53 +02:00
|
|
|
|
|
|
|
my $artifact_id = $login->assertionArtifact();
|
|
|
|
|
|
|
|
# Load artifact message into login response
|
2010-04-12 17:03:54 +02:00
|
|
|
my $art_session = $self->loadArtifact($artifact_id);
|
|
|
|
eval { $login->set_artifact_message( $art_session->{message} ); };
|
2010-04-12 11:09:53 +02:00
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
$self->lmLog( "Cannot load artifact message", 'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Response loaded", 'debug' );
|
|
|
|
|
2010-07-01 11:48:50 +02:00
|
|
|
# Try to get Lasso session
|
2010-08-31 16:36:45 +02:00
|
|
|
my $session_id = $art_session->{_saml_id};
|
2010-07-01 11:48:50 +02:00
|
|
|
if ($session_id) {
|
|
|
|
$self->lmLog( "Find session_id $session_id in artifact session",
|
2010-07-02 10:54:54 +02:00
|
|
|
'debug' );
|
2010-04-12 17:03:54 +02:00
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
my $session = $self->getApacheSession( $session_id, 1 );
|
|
|
|
unless ( defined $session ) {
|
|
|
|
$self->lmLog( "Unable to open session $session_id", 'error' );
|
|
|
|
return;
|
|
|
|
}
|
2010-04-12 17:03:54 +02:00
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
my $lassoSession = $session->{_lassoSessionDump};
|
2010-04-12 17:03:54 +02:00
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
if ($lassoSession) {
|
|
|
|
unless ( $self->setSessionFromDump( $login, $lassoSession ) ) {
|
|
|
|
$self->lmLog( "Unable to load Lasso Session", 'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$self->lmLog( "Lasso Session loaded", 'debug' );
|
2010-04-12 17:03:54 +02:00
|
|
|
}
|
|
|
|
|
2010-07-01 11:48:50 +02:00
|
|
|
}
|
|
|
|
else {
|
2010-07-02 10:54:54 +02:00
|
|
|
$self->lmLog( "No session_id in artifact session", 'debug' );
|
2010-07-01 11:48:50 +02:00
|
|
|
}
|
|
|
|
|
2010-04-12 11:09:53 +02:00
|
|
|
# Build artifact response
|
|
|
|
eval { Lasso::Login::build_response_msg($login); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
$self->lmLog( "Cannot build artifact response", 'error' );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$self->lmLog( "Artifact response built", 'debug' );
|
|
|
|
|
2010-07-01 11:48:50 +02:00
|
|
|
# Store Lasso session if session opened
|
|
|
|
if ( $session_id and $login->is_session_dirty ) {
|
2010-04-12 17:03:54 +02:00
|
|
|
$self->lmLog( "Save Lasso session in session", 'debug' );
|
|
|
|
$self->updateSession(
|
|
|
|
{ _lassoSessionDump => $login->get_session->dump }, $session_id );
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return artifact message
|
2010-04-12 11:09:53 +02:00
|
|
|
return $login->msg_body;
|
|
|
|
}
|
|
|
|
|
2010-03-26 14:56:37 +01:00
|
|
|
## @method boolean processArtRequestMsg(Lasso::Profile profile, string request)
|
|
|
|
# Process artifact request message
|
|
|
|
# @param profile Lasso::Profile object
|
|
|
|
# @param response SAML request
|
|
|
|
# @return result
|
|
|
|
sub processArtRequestMsg {
|
|
|
|
my ( $self, $profile, $request ) = splice @_;
|
|
|
|
|
|
|
|
# Login profile
|
|
|
|
if ( $profile->isa("Lasso::Login") ) {
|
|
|
|
|
|
|
|
eval { Lasso::Login::process_request_msg( $profile, $request ); };
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-24 16:24:54 +01:00
|
|
|
## @method boolean processArtResponseMsg(Lasso::Profile profile, string response)
|
|
|
|
# Process artifact response message
|
|
|
|
# @param profile Lasso::Profile object
|
|
|
|
# @param response SAML response
|
|
|
|
# @return result
|
|
|
|
sub processArtResponseMsg {
|
|
|
|
my ( $self, $profile, $response ) = splice @_;
|
|
|
|
|
|
|
|
# Login profile
|
|
|
|
if ( $profile->isa("Lasso::Login") ) {
|
|
|
|
|
|
|
|
eval { Lasso::Login::process_response_msg( $profile, $response ); };
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-26 10:12:18 +01:00
|
|
|
## @method string sendSOAPMessage(string endpoint, string message)
|
|
|
|
# Send SOAP message and get response
|
|
|
|
# @param endpoint SOAP End Point
|
|
|
|
# @param message SOAP message
|
|
|
|
# @return SOAP response
|
|
|
|
sub sendSOAPMessage {
|
|
|
|
my ( $self, $endpoint, $message ) = splice @_;
|
|
|
|
my $response;
|
|
|
|
|
|
|
|
# LWP User Agent
|
|
|
|
my $ua = new LWP::UserAgent;
|
|
|
|
push @{ $ua->requests_redirectable }, 'POST';
|
|
|
|
|
|
|
|
my $request = HTTP::Request->new( 'POST' => $endpoint );
|
|
|
|
$request->content_type('text/xml');
|
|
|
|
$request->content($message);
|
|
|
|
|
|
|
|
$self->lmLog( "Send SOAP message $message to $endpoint", 'debug' );
|
|
|
|
|
|
|
|
# SOAP call
|
|
|
|
my $soap_answer = $ua->request($request);
|
|
|
|
if ( $soap_answer->code() == "200" ) {
|
|
|
|
$response = $soap_answer->content();
|
|
|
|
$self->lmLog( "Get response $response", 'debug' );
|
|
|
|
}
|
2010-03-03 17:54:23 +01:00
|
|
|
else {
|
|
|
|
$self->lmLog( "No response to SOAP request", 'debug' );
|
|
|
|
return;
|
|
|
|
}
|
2010-02-26 10:12:18 +01:00
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
2010-06-01 17:34:08 +02:00
|
|
|
## @method Lasso::AssertionQuery createAssertionQuery(Lasso::Server server)
|
|
|
|
# Create a new assertion query
|
|
|
|
# @param server Lasso::Server object
|
|
|
|
# @return assertion query
|
|
|
|
sub createAssertionQuery {
|
|
|
|
my ( $self, $server ) = splice @_;
|
|
|
|
my $query;
|
|
|
|
|
|
|
|
# Create assertion query
|
|
|
|
eval { $query = Lasso::AssertionQuery->new($server); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
2010-06-01 16:43:49 +02:00
|
|
|
## @method Lasso::AssertionQuery createAttributeRequest(Lasso::Server server, string idp, hashref attributes, Lasso::Saml2NameID nameid)
|
2010-03-03 17:54:23 +01:00
|
|
|
# Create an attribute request
|
|
|
|
# @param server Lasso::Server object
|
|
|
|
# @param idp IDP entityID
|
|
|
|
# @param attributes List of requested attributes
|
2010-06-01 16:43:49 +02:00
|
|
|
# @param nameid Subject NameID
|
|
|
|
# @return attribute request
|
2010-03-03 17:54:23 +01:00
|
|
|
sub createAttributeRequest {
|
2010-06-01 16:43:49 +02:00
|
|
|
my ( $self, $server, $idp, $attributes, $nameid ) = splice @_;
|
2010-03-03 17:54:23 +01:00
|
|
|
my $query;
|
|
|
|
|
|
|
|
# Create assertion query
|
2010-06-01 17:42:35 +02:00
|
|
|
return unless ( $query = $self->createAssertionQuery($server) );
|
2010-03-03 17:54:23 +01:00
|
|
|
|
|
|
|
$self->lmLog( "Assertion query created", 'debug' );
|
|
|
|
|
|
|
|
# Init request
|
|
|
|
my $method = Lasso::Constants::HTTP_METHOD_SOAP;
|
|
|
|
my $type = Lasso::Constants::ASSERTION_QUERY_REQUEST_TYPE_ATTRIBUTE;
|
|
|
|
eval {
|
|
|
|
Lasso::AssertionQuery::init_request( $query, $idp, $method, $type );
|
|
|
|
};
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Assertion query request initiated", 'debug' );
|
|
|
|
|
2010-06-01 16:43:49 +02:00
|
|
|
# Set NameID
|
2010-06-11 15:49:33 +02:00
|
|
|
eval { $query->request()->Subject()->NameID($nameid); };
|
2010-06-01 16:43:49 +02:00
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-06-04 16:23:41 +02:00
|
|
|
$self->lmLog( "Set NameID " . $nameid->dump . " in assertion query",
|
|
|
|
'debug' );
|
2010-06-02 17:21:39 +02:00
|
|
|
|
2010-03-03 17:54:23 +01:00
|
|
|
# Store attributes in request
|
|
|
|
my @requested_attributes;
|
|
|
|
foreach ( keys %$attributes ) {
|
|
|
|
|
|
|
|
# Create SAML2 Attribute
|
|
|
|
my $attribute;
|
|
|
|
|
|
|
|
eval { $attribute = Lasso::Saml2Attribute->new(); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set attribute properties
|
|
|
|
my ( $mandatory, $name, $format, $friendly_name ) =
|
|
|
|
split( /;/, $attributes->{$_} );
|
|
|
|
|
|
|
|
$attribute->Name($name) if defined $name;
|
|
|
|
$attribute->NameFormat($format) if defined $format;
|
|
|
|
$attribute->FriendlyName($friendly_name) if defined $friendly_name;
|
|
|
|
|
|
|
|
# Store attribute
|
|
|
|
push @requested_attributes, $attribute;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set attributes in request
|
|
|
|
eval { $query->request()->Attribute(@requested_attributes); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Build message
|
|
|
|
eval { Lasso::AssertionQuery::build_request_msg($query); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return query
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
2010-06-02 10:09:59 +02:00
|
|
|
## @method boolean validateAttributeRequest(Lasso::AssertionQuery query)
|
|
|
|
# Validate an attribute request
|
|
|
|
# @param query Lasso::AssertionQuery object
|
|
|
|
# @return result
|
|
|
|
sub validateAttributeRequest {
|
|
|
|
my ( $self, $query ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::AssertionQuery::validate_request($query); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method Lasso::AssertionQuery processAttributeRequest(Lasso::Server server, string request)
|
|
|
|
# Process an attribute request
|
|
|
|
# @param server Lasso::Server object
|
|
|
|
# @param request Request content
|
|
|
|
# @return assertion query
|
|
|
|
sub processAttributeRequest {
|
|
|
|
my ( $self, $server, $request ) = splice @_;
|
|
|
|
my $query;
|
|
|
|
|
|
|
|
# Create assertion query
|
|
|
|
return unless ( $query = $self->createAssertionQuery($server) );
|
|
|
|
|
|
|
|
$self->lmLog( "Assertion query created", 'debug' );
|
|
|
|
|
|
|
|
# Process response
|
|
|
|
eval { Lasso::AssertionQuery::process_request_msg( $query, $request ); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Attribute request is valid", 'debug' );
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
2010-06-02 15:45:37 +02:00
|
|
|
## @method string buildAttributeResponse(Lasso::AssertionQuery query)
|
|
|
|
# Build attribute response
|
|
|
|
# @param query Lasso::AssertionQuery object
|
|
|
|
# @return attribute response
|
|
|
|
sub buildAttributeResponse {
|
|
|
|
my ( $self, $query ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::AssertionQuery::build_response_msg($query); };
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $query->msg_body;
|
|
|
|
}
|
|
|
|
|
2010-03-03 17:54:23 +01:00
|
|
|
## @method Lasso::AssertionQuery processAttributeResponse(Lasso::Server server, string response)
|
|
|
|
# Process an attribute response
|
|
|
|
# @param server Lasso::Server object
|
|
|
|
# @param response Response content
|
|
|
|
# @return assertion query
|
|
|
|
sub processAttributeResponse {
|
|
|
|
my ( $self, $server, $response ) = splice @_;
|
|
|
|
my $query;
|
|
|
|
|
|
|
|
# Create assertion query
|
2010-06-01 17:42:35 +02:00
|
|
|
return unless ( $query = $self->createAssertionQuery($server) );
|
2010-03-03 17:54:23 +01:00
|
|
|
|
|
|
|
$self->lmLog( "Assertion query created", 'debug' );
|
|
|
|
|
|
|
|
# Process response
|
|
|
|
eval { Lasso::AssertionQuery::process_response_msg( $query, $response ); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Attribute response is valid", 'debug' );
|
|
|
|
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
2010-03-05 10:28:28 +01:00
|
|
|
## @method string getNameIDFormat(string format)
|
|
|
|
# Convert configuration string into SAML2 NameIDFormat string
|
|
|
|
# @param format configuration string
|
|
|
|
# @return SAML2 NameIDFormat string
|
|
|
|
sub getNameIDFormat {
|
|
|
|
my ( $self, $format ) = splice @_;
|
|
|
|
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED
|
|
|
|
if ( $format =~ /unspecified/i );
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_EMAIL
|
|
|
|
if ( $format =~ /email/i );
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_X509
|
|
|
|
if ( $format =~ /x509/i );
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_WINDOWS
|
|
|
|
if ( $format =~ /windows/i );
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_KERBEROS
|
|
|
|
if ( $format =~ /kerberos/i );
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_ENTITY
|
|
|
|
if ( $format =~ /entity/i );
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
|
|
|
|
if ( $format =~ /persistent/i );
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT
|
|
|
|
if ( $format =~ /transient/i );
|
|
|
|
return Lasso::Constants::SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED
|
|
|
|
if ( $format =~ /encrypted/i );
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-03-05 17:57:11 +01:00
|
|
|
## @method int getHttpMethod(string method)
|
|
|
|
# Convert configuration string into Lasso HTTP Method integer
|
|
|
|
# @param method configuration string
|
|
|
|
# @return Lasso HTTP Method integer
|
|
|
|
sub getHttpMethod {
|
|
|
|
my ( $self, $method ) = splice @_;
|
|
|
|
|
|
|
|
return Lasso::Constants::HTTP_METHOD_POST
|
|
|
|
if ( $method =~ /^(http)?[-_]?post$/i );
|
|
|
|
return Lasso::Constants::HTTP_METHOD_REDIRECT
|
|
|
|
if ( $method =~ /^(http)?[-_]?redirect$/i );
|
|
|
|
return Lasso::Constants::HTTP_METHOD_SOAP
|
|
|
|
if ( $method =~ /^(http)?[-_]?soap$/i );
|
|
|
|
return Lasso::Constants::HTTP_METHOD_ARTIFACT_GET
|
|
|
|
if ( $method =~ /^(artifact)[-_]get$/i );
|
|
|
|
return Lasso::Constants::HTTP_METHOD_ARTIFACT_POST
|
|
|
|
if ( $method =~ /^(artifact)[-_]post$/i );
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-28 14:17:05 +02:00
|
|
|
## @method int getHttpMethodString(int method)
|
|
|
|
# Convert configuration Lasso HTTP Method integer into string
|
|
|
|
# @param method Lasso HTTP Method
|
|
|
|
# @return method string
|
|
|
|
sub getHttpMethodString {
|
|
|
|
my ( $self, $method ) = splice @_;
|
|
|
|
|
2010-06-21 17:29:59 +02:00
|
|
|
return "POST" if ( $method == Lasso::Constants::HTTP_METHOD_POST );
|
2010-06-04 17:54:52 +02:00
|
|
|
return "REDIRECT"
|
|
|
|
if ( $method == Lasso::Constants::HTTP_METHOD_REDIRECT );
|
2010-06-21 17:29:59 +02:00
|
|
|
return "SOAP" if ( $method == Lasso::Constants::HTTP_METHOD_SOAP );
|
2010-05-28 14:17:05 +02:00
|
|
|
return "ARTIFACT GET"
|
|
|
|
if ( $method == Lasso::Constants::HTTP_METHOD_ARTIFACT_GET );
|
|
|
|
return "ARTIFACT POST"
|
|
|
|
if ( $method == Lasso::Constants::HTTP_METHOD_ARTIFACT_POST );
|
|
|
|
|
|
|
|
return "UNDEFINED";
|
|
|
|
}
|
2010-03-05 17:57:11 +01:00
|
|
|
## @method int getFirstHttpMethod(Lasso::Server server, string entityID, int protcolType)
|
|
|
|
# Find a suitable HTTP method for an entity with a given protocol
|
|
|
|
# @param server Lasso::Server object
|
|
|
|
# @param entityID entity ID
|
|
|
|
# @param protocolType Lasso protocol type
|
|
|
|
# @return Lasso HTTP Method
|
|
|
|
sub getFirstHttpMethod {
|
|
|
|
my ( $self, $server, $entityID, $protocolType ) = splice @_;
|
|
|
|
my $entity_provider;
|
|
|
|
my $method;
|
|
|
|
|
|
|
|
# Get Lasso::Provider object
|
|
|
|
eval {
|
|
|
|
$entity_provider = Lasso::Server::get_provider( $server, $entityID );
|
|
|
|
};
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Find HTTP method
|
|
|
|
eval {
|
|
|
|
$method =
|
|
|
|
Lasso::Provider::get_first_http_method( $server, $entity_provider,
|
|
|
|
$protocolType );
|
|
|
|
};
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $method;
|
|
|
|
}
|
|
|
|
|
2010-04-01 14:51:32 +02:00
|
|
|
## @method boolean disableSignature(Lasso::Profile profile)
|
|
|
|
# Modify Lasso signature hint to disable signature
|
|
|
|
# @param profile Lasso profile object
|
|
|
|
# @return result
|
|
|
|
sub disableSignature {
|
|
|
|
my ( $self, $profile ) = splice @_;
|
|
|
|
|
|
|
|
eval {
|
|
|
|
Lasso::Profile::set_signature_hint( $profile,
|
|
|
|
Lasso::Constants::PROFILE_SIGNATURE_HINT_FORBID );
|
|
|
|
};
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-01 16:18:37 +02:00
|
|
|
## @method boolean forceSignature(Lasso::Profile profile)
|
|
|
|
# Modify Lasso signature hint to force signature
|
|
|
|
# @param profile Lasso profile object
|
|
|
|
# @return result
|
|
|
|
sub forceSignature {
|
|
|
|
my ( $self, $profile ) = splice @_;
|
|
|
|
|
|
|
|
eval {
|
|
|
|
Lasso::Profile::set_signature_hint( $profile,
|
|
|
|
Lasso::Constants::PROFILE_SIGNATURE_HINT_FORCE );
|
|
|
|
};
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-16 12:13:20 +02:00
|
|
|
## @method boolean disableSignatureVerification(Lasso::Profile profile)
|
|
|
|
# Modify Lasso signature hint to disable signature verification
|
|
|
|
# @param profile Lasso profile object
|
|
|
|
# @return result
|
|
|
|
sub disableSignatureVerification {
|
|
|
|
my ( $self, $profile ) = splice @_;
|
|
|
|
|
|
|
|
eval {
|
|
|
|
Lasso::Profile::set_signature_verify_hint( $profile,
|
2010-04-30 16:55:40 +02:00
|
|
|
Lasso::Constants::PROFILE_SIGNATURE_VERIFY_HINT_IGNORE );
|
2010-04-16 12:13:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-04-08 11:39:53 +02:00
|
|
|
## @method string getAuthnContext(string context)
|
2010-04-01 18:32:51 +02:00
|
|
|
# Convert configuration string into SAML2 AuthnContextClassRef string
|
|
|
|
# @param context configuration string
|
|
|
|
# @return SAML2 AuthnContextClassRef string
|
|
|
|
sub getAuthnContext {
|
|
|
|
my ( $self, $context ) = splice @_;
|
|
|
|
|
|
|
|
return Lasso::Constants::SAML2_AUTHN_CONTEXT_KERBEROS
|
|
|
|
if ( $context =~ /^kerberos$/i );
|
|
|
|
return Lasso::Constants::SAML2_AUTHN_CONTEXT_PASSWORD_PROTECTED_TRANSPORT
|
|
|
|
if ( $context =~ /^password[-_ ]protected[-_ ]transport$/i );
|
|
|
|
return Lasso::Constants::SAML2_AUTHN_CONTEXT_PASSWORD
|
|
|
|
if ( $context =~ /^password$/i );
|
|
|
|
return Lasso::Constants::SAML2_AUTHN_CONTEXT_X509
|
|
|
|
if ( $context =~ /^x509$/i );
|
2010-04-15 11:06:53 +02:00
|
|
|
return Lasso::Constants::SAML2_AUTHN_CONTEXT_TLS_CLIENT
|
|
|
|
if ( $context =~ /^tls[-_ ]client$/i );
|
2010-04-14 18:22:55 +02:00
|
|
|
return Lasso::Constants::SAML2_AUTHN_CONTEXT_UNSPECIFIED
|
|
|
|
if ( $context =~ /^unspecified$/i );
|
2010-04-01 18:32:51 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-04-08 11:39:53 +02:00
|
|
|
## @method string timestamp2samldate(string timestamp)
|
|
|
|
# Convert timestamp into SAML2 date format
|
|
|
|
# @param timestamp UNIX timestamp
|
|
|
|
# @return SAML2 date
|
|
|
|
sub timestamp2samldate {
|
|
|
|
my ( $self, $timestamp ) = splice @_;
|
|
|
|
|
2010-05-02 13:37:25 +02:00
|
|
|
my @t = gmtime($timestamp);
|
2010-05-12 14:46:47 +02:00
|
|
|
my $samldate = POSIX::strftime( "%Y-%m-%dT%TZ", @t );
|
|
|
|
|
|
|
|
$self->lmLog( "Convert timestamp $timestamp in SAML2 date: $samldate",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
return $samldate;
|
2010-04-08 11:39:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
## @method string samldate2timestamp(string samldate)
|
|
|
|
# Convert SAML2 date format into timestamp
|
2010-05-31 15:50:26 +02:00
|
|
|
# @param samldate SAML2 date format
|
2010-04-08 11:39:53 +02:00
|
|
|
# @return UNIX timestamp
|
|
|
|
sub samldate2timestamp {
|
|
|
|
my ( $self, $samldate ) = splice @_;
|
|
|
|
|
2010-06-11 12:17:43 +02:00
|
|
|
my ( $year, $mon, $mday, $hour, $min, $sec, $msec, $ztime ) = ( $samldate =~
|
|
|
|
/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z)?/ );
|
2010-04-08 11:39:53 +02:00
|
|
|
|
2010-05-12 17:14:07 +02:00
|
|
|
my $timestamp =
|
|
|
|
timegm( $sec, $min, $hour, $mday, $mon - 1, $year - 1900, 0 );
|
2010-04-08 11:39:53 +02:00
|
|
|
|
|
|
|
$self->lmLog( "Convert SAML2 date $samldate in timestamp: $timestamp",
|
|
|
|
'debug' );
|
|
|
|
|
|
|
|
return $timestamp;
|
|
|
|
}
|
|
|
|
|
2010-06-21 18:24:50 +02:00
|
|
|
## @pmethod int sendLogoutResponseToServiceProvider(Lasso::Logout $logout, int $method)
|
2010-04-26 19:06:49 +02:00
|
|
|
# Send logout response issue from a logout request.
|
|
|
|
# @param $logout Lasso Logout object
|
|
|
|
# @param $method Method to use
|
|
|
|
# @return boolean False if failed.
|
|
|
|
sub sendLogoutResponseToServiceProvider {
|
2010-06-21 18:24:50 +02:00
|
|
|
my ( $self, $logout, $method ) = splice @_;
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
# Logout response
|
|
|
|
unless ( $self->buildLogoutResponseMsg($logout) ) {
|
|
|
|
$self->lmLog( "Unable to build SLO response", 'error' );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# 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->{urldc} = $slo_url;
|
|
|
|
|
|
|
|
$self->lmLog( "Redirect user to $slo_url", 'debug' );
|
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
$self->_subProcess(qw(autoRedirect));
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
# If we are here, there was a problem with HTTP-REDIRECT response
|
|
|
|
$self->lmLog( "Logout response was not sent trough GET", 'error' );
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
return 0;
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-09-01 14:56:15 +02:00
|
|
|
}
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
# HTTP-POST
|
2010-05-02 13:37:25 +02:00
|
|
|
elsif ( $method == Lasso::Constants::HTTP_METHOD_POST ) {
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
# Use autosubmit form
|
2010-09-01 14:56:15 +02:00
|
|
|
my $slo_url = $logout->msg_url;
|
|
|
|
my $slo_body = $logout->msg_body;
|
2010-06-21 18:24:50 +02:00
|
|
|
my $relaystate = $logout->msg_relayState;
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
$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' );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# HTTP-SOAP
|
2010-05-02 13:37:25 +02:00
|
|
|
elsif ( $method == Lasso::Constants::HTTP_METHOD_SOAP ) {
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
my $slo_body = $logout->msg_body;
|
|
|
|
$self->{SOAPMessage} = $slo_body;
|
|
|
|
|
|
|
|
$self->lmLog( "SOAP response $slo_body", 'debug' );
|
|
|
|
|
|
|
|
$self->_subProcess(qw(returnSOAPMessage));
|
|
|
|
|
|
|
|
# If we are here, there was a problem with SOAP response
|
2010-04-28 21:57:16 +02:00
|
|
|
$self->lmLog( "Logout response was not sent trough SOAP", 'error' );
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-07-03 16:38:46 +02:00
|
|
|
## @pmethod int sendLogoutRequestToProvider(Lasso::Logout $logout, string $providerID, int $method, boolean $relay, string $relayState)
|
|
|
|
# Send a logout request to a provider
|
2010-04-26 19:06:49 +02:00
|
|
|
# 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
|
|
|
|
# @param $providerID The concerned service provider
|
|
|
|
# @param $method The method used to send the logout request
|
2010-04-28 19:16:38 +02:00
|
|
|
# @param $relay If SOAP method, build a relay logout request
|
2010-06-21 16:28:42 +02:00
|
|
|
# @param $relayState Relay State for SLO status
|
2010-04-26 19:06:49 +02:00
|
|
|
# @return int Number of concerned providers.
|
2010-07-03 16:38:46 +02:00
|
|
|
sub sendLogoutRequestToProvider {
|
2010-06-21 16:28:42 +02:00
|
|
|
my ( $self, $logout, $providerID, $method, $relay, $relayState ) =
|
|
|
|
splice @_;
|
2010-05-02 13:37:25 +02:00
|
|
|
my $server = $self->{_lassoServer};
|
2010-04-26 19:06:49 +02:00
|
|
|
my $info;
|
|
|
|
|
|
|
|
# Test if provider is mentionned
|
|
|
|
if ( !$providerID ) {
|
|
|
|
return ( 0, undef, undef );
|
|
|
|
}
|
|
|
|
|
2010-07-03 16:38:46 +02:00
|
|
|
my $type = defined $self->{_spList}->{$providerID} ? "SP" : "IDP";
|
|
|
|
|
|
|
|
# Find EntityID in spList or idpList
|
|
|
|
unless ( defined $self->{ '_' . lc($type) . 'List' }->{$providerID} ) {
|
|
|
|
$self->lmLog( "$providerID does not match any known $type", 'error' );
|
2010-04-26 19:06:49 +02:00
|
|
|
return ( 0, undef, undef );
|
|
|
|
}
|
|
|
|
|
2010-07-03 16:38:46 +02:00
|
|
|
# Get Provider Name and Conf Key from EntityID
|
|
|
|
my $providerName =
|
|
|
|
$self->{ '_' . lc($type) . 'List' }->{$providerID}->{name};
|
|
|
|
my $confKey = $self->{ '_' . lc($type) . 'List' }->{$providerID}->{confKey};
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
# Get first HTTP method
|
|
|
|
my $protocolType = Lasso::Constants::MD_PROTOCOL_TYPE_SINGLE_LOGOUT;
|
|
|
|
if ( !$method ) {
|
2010-04-28 12:28:21 +02:00
|
|
|
$method =
|
|
|
|
$self->getFirstHttpMethod( $server, $providerID, $protocolType );
|
2010-04-26 19:06:49 +02:00
|
|
|
}
|
|
|
|
|
2010-04-29 15:39:26 +02:00
|
|
|
# Fix a default value for the relay parameter
|
|
|
|
$relay = 0 unless ( defined $relay );
|
|
|
|
|
2010-05-20 15:08:07 +02:00
|
|
|
# Signature
|
|
|
|
my $signSLOMessage =
|
2010-07-03 16:38:46 +02:00
|
|
|
$self->{ 'saml' . $type . 'MetaDataOptions' }->{$confKey}
|
|
|
|
->{ 'saml' . $type . 'MetaDataOptionsSignSLOMessage' };
|
2010-05-20 15:08:07 +02:00
|
|
|
|
2010-07-01 18:05:57 +02:00
|
|
|
if ( $signSLOMessage == 0 ) {
|
|
|
|
$self->lmLog( "SLO request will not be signed", 'debug' );
|
|
|
|
$self->disableSignature($logout);
|
|
|
|
}
|
|
|
|
elsif ( $signSLOMessage == 1 ) {
|
|
|
|
$self->lmLog( "SLO request will be signed", 'debug' );
|
|
|
|
$self->forceSignature($logout);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog( "SLO request signature according to metadata", 'debug' );
|
2010-05-20 15:08:07 +02:00
|
|
|
}
|
|
|
|
|
2010-06-21 16:28:42 +02:00
|
|
|
# Relay State
|
|
|
|
if ($relayState) {
|
|
|
|
eval { $logout->msg_relayState($relayState); };
|
|
|
|
if ($@) {
|
|
|
|
$self->lmLog(
|
2010-07-03 16:38:46 +02:00
|
|
|
"Unable to set Relay State $relayState in SLO request for $confKey",
|
2010-06-21 16:28:42 +02:00
|
|
|
'error'
|
|
|
|
);
|
|
|
|
return ( 0, $method, undef );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-29 15:39:26 +02:00
|
|
|
# Build the request unless this is a SOAP relay logout request
|
|
|
|
unless ( $method == Lasso::Constants::HTTP_METHOD_SOAP && $relay ) {
|
|
|
|
|
|
|
|
$self->lmLog( "No logout request found, build it", 'debug' );
|
|
|
|
|
2010-05-02 13:37:25 +02:00
|
|
|
# Initiate the logout request
|
|
|
|
unless ( $self->initLogoutRequest( $logout, $providerID, $method ) ) {
|
|
|
|
$self->lmLog( "Initiate logout request failed for $providerID",
|
|
|
|
'error' );
|
|
|
|
return ( 0, $method, undef );
|
|
|
|
}
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-05-02 13:37:25 +02:00
|
|
|
# Build request message
|
|
|
|
unless ( $self->buildLogoutRequestMsg($logout) ) {
|
2010-04-30 16:55:40 +02:00
|
|
|
$self->lmLog( "Build logout request failed for $providerID",
|
|
|
|
'error' );
|
2010-05-02 13:37:25 +02:00
|
|
|
return ( 0, $method, undef );
|
|
|
|
}
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-04-29 15:39:26 +02:00
|
|
|
}
|
|
|
|
|
2010-07-05 23:24:34 +02:00
|
|
|
# Keep message ID in memory to prevent replay
|
|
|
|
my $samlID = $logout->request()->ID;
|
|
|
|
unless ( $self->storeReplayProtection($samlID) ) {
|
|
|
|
$self->lmLog( "Unable to store message ID", 'error' );
|
|
|
|
return ( 0, $method, undef );
|
|
|
|
}
|
|
|
|
|
2010-04-26 19:06:49 +02:00
|
|
|
# Send logout request to the provider depending of the request method
|
|
|
|
# HTTP-REDIRECT
|
|
|
|
if ( $method == Lasso::Constants::HTTP_METHOD_REDIRECT ) {
|
|
|
|
|
2010-04-28 16:29:52 +02:00
|
|
|
$self->lmLog( "Send HTTP-REDIRECT logout request to $providerID",
|
2010-04-28 21:57:16 +02:00
|
|
|
'debug' );
|
2010-04-28 16:29:52 +02:00
|
|
|
|
2010-04-26 19:06:49 +02:00
|
|
|
# Redirect user to response URL
|
|
|
|
my $slo_url = $logout->msg_url;
|
|
|
|
|
2010-06-16 18:17:05 +02:00
|
|
|
$info .=
|
|
|
|
'<tr>' . '<td>'
|
2010-04-28 21:57:16 +02:00
|
|
|
. '<iframe src="'
|
|
|
|
. $slo_url
|
|
|
|
. '" alt="" marginwidth="0"'
|
|
|
|
. ' marginheight="0" scrolling="no" style="border: none"'
|
2010-06-16 18:17:05 +02:00
|
|
|
. ' width="10px" height="10px" frameborder="0">'
|
|
|
|
. '</iframe>' . '</td>' . '<td>'
|
|
|
|
. $providerName . '</td>' . '</tr>';
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# HTTP-POST
|
2010-05-02 13:37:25 +02:00
|
|
|
elsif ( $method == Lasso::Constants::HTTP_METHOD_POST ) {
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-06-16 12:32:43 +02:00
|
|
|
$self->lmLog( "Build POST relay logout request to $providerID",
|
|
|
|
'debug' );
|
2010-04-28 16:29:52 +02:00
|
|
|
|
2010-06-16 12:32:43 +02:00
|
|
|
# Create a new relay session
|
|
|
|
my $relayInfos = $self->getSamlSession();
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-06-16 12:32:43 +02:00
|
|
|
# Store infos
|
2010-09-01 14:56:15 +02:00
|
|
|
$relayInfos->{type} = 'relay';
|
|
|
|
$relayInfos->{_utime} = time;
|
|
|
|
$relayInfos->{url} = $logout->msg_url;
|
|
|
|
$relayInfos->{body} = $logout->msg_body;
|
2010-06-21 16:28:42 +02:00
|
|
|
$relayInfos->{relayState} = $logout->msg_relayState;
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-06-16 12:32:43 +02:00
|
|
|
my $relayID = $relayInfos->{_session_id};
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-06-16 12:32:43 +02:00
|
|
|
# Build the URL that could be used to play this logout request
|
|
|
|
my $slo_url =
|
|
|
|
$self->{portal} . '/saml/relaySingleLogoutPOST?relay=' . $relayID;
|
|
|
|
|
|
|
|
# Create iFrame
|
2010-06-16 18:17:05 +02:00
|
|
|
$info .=
|
|
|
|
'<tr>' . '<td>'
|
2010-06-16 12:32:43 +02:00
|
|
|
. '<iframe src="'
|
|
|
|
. $slo_url
|
|
|
|
. '" alt="" marginwidth="0"'
|
|
|
|
. ' marginheight="0" scrolling="no" style="border: none"'
|
2010-06-16 18:17:05 +02:00
|
|
|
. ' width="10px" height="10px" frameborder="0">'
|
|
|
|
. '</iframe>' . '</td>' . '<td>'
|
|
|
|
. $providerName . '</td>' . '</tr>';
|
2010-04-26 19:06:49 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# HTTP-SOAP
|
2010-05-02 13:37:25 +02:00
|
|
|
elsif ( $method == Lasso::Constants::HTTP_METHOD_SOAP ) {
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-04-28 19:16:38 +02:00
|
|
|
# Build a relay request, to be used after SLO process is done
|
2010-04-28 21:57:16 +02:00
|
|
|
if ($relay) {
|
2010-04-28 19:16:38 +02:00
|
|
|
|
2010-04-29 15:39:26 +02:00
|
|
|
$self->lmLog( "Build SOAP relay logout request for $providerID",
|
2010-04-28 21:57:16 +02:00
|
|
|
'debug' );
|
2010-04-28 19:16:38 +02:00
|
|
|
|
2010-06-21 16:28:42 +02:00
|
|
|
# Create a new relay session
|
|
|
|
my $relayInfos = $self->getSamlSession();
|
2010-04-29 15:39:26 +02:00
|
|
|
|
|
|
|
# Build needed information to be stored into samlStorage
|
|
|
|
unless ( $logout->get_session() && $logout->get_identity() ) {
|
|
|
|
$self->lmLog(
|
|
|
|
"No session and identity found into logout object",
|
|
|
|
'error' );
|
|
|
|
return ( 0, $method, undef );
|
|
|
|
}
|
2010-04-28 19:16:38 +02:00
|
|
|
|
2010-06-21 16:28:42 +02:00
|
|
|
$relayInfos->{type} = 'relay';
|
|
|
|
$relayInfos->{_utime} = time;
|
|
|
|
$relayInfos->{_lassoSessionDump} = $logout->get_session->dump;
|
|
|
|
$relayInfos->{_lassoIdentityDump} = $logout->get_identity->dump;
|
|
|
|
$relayInfos->{_providerID} = $providerID;
|
|
|
|
$relayInfos->{_relayState} = $logout->msg_relayState;
|
2010-04-28 19:16:38 +02:00
|
|
|
|
2010-06-21 16:28:42 +02:00
|
|
|
my $relayID = $relayInfos->{_session_id};
|
2010-04-28 19:16:38 +02:00
|
|
|
|
|
|
|
# Build the URL that could be used to play this logout request
|
2010-04-30 16:55:40 +02:00
|
|
|
my $slo_url =
|
2010-06-21 16:28:42 +02:00
|
|
|
$self->{portal} . '/saml/relaySingleLogoutSOAP?relay=' . $relayID;
|
2010-04-28 19:16:38 +02:00
|
|
|
|
|
|
|
# Display information to the user
|
2010-06-16 18:17:05 +02:00
|
|
|
$info .= '<tr>'
|
|
|
|
. '<td><img src="'
|
2010-04-30 16:55:40 +02:00
|
|
|
. $slo_url
|
2010-06-16 18:17:05 +02:00
|
|
|
. '" width="10px" height="10px" />' . '</td>' . '<td>'
|
|
|
|
. $providerName . '</td>' . '</tr>';
|
2010-04-28 19:16:38 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# Send the request directly
|
|
|
|
else {
|
|
|
|
|
2010-04-28 21:57:16 +02:00
|
|
|
$self->lmLog( "Send SOAP logout request to $providerID", 'debug' );
|
2010-04-28 16:29:52 +02:00
|
|
|
|
2010-04-28 21:57:16 +02:00
|
|
|
my $slo_url = $logout->msg_url;
|
|
|
|
my $slo_body = $logout->msg_body;
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-04-28 21:57:16 +02:00
|
|
|
# Send SOAP request and manage response
|
|
|
|
my $sp_response = $self->sendSOAPMessage( $slo_url, $slo_body );
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-04-28 21:57:16 +02:00
|
|
|
unless ($sp_response) {
|
|
|
|
$self->lmLog( "No logout response to SOAP request", 'error' );
|
|
|
|
return ( 0, $method, undef );
|
|
|
|
}
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-04-28 21:57:16 +02:00
|
|
|
# Process logout response
|
|
|
|
my $sp_result =
|
|
|
|
$self->processLogoutResponseMsg( $logout, $sp_response );
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-04-28 21:57:16 +02:00
|
|
|
unless ($sp_result) {
|
|
|
|
$self->lmLog( "Fail to process logout response", 'error' );
|
|
|
|
return ( 0, $method, undef );
|
|
|
|
}
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-06-21 16:28:42 +02:00
|
|
|
# Store success status for this SLO request
|
|
|
|
my $sloStatusSessionInfos = $self->getSamlSession($relayState);
|
|
|
|
|
|
|
|
if ($sloStatusSessionInfos) {
|
2010-07-03 16:38:46 +02:00
|
|
|
$sloStatusSessionInfos->{$confKey} = 1;
|
2010-06-21 16:28:42 +02:00
|
|
|
untie %$sloStatusSessionInfos;
|
|
|
|
$self->lmLog(
|
2010-07-03 16:38:46 +02:00
|
|
|
"Store SLO status for $confKey in session $relayState",
|
2010-06-21 16:28:42 +02:00
|
|
|
'debug' );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog(
|
2010-07-03 16:38:46 +02:00
|
|
|
"Unable to store SLO status for $confKey in session $relayState",
|
2010-06-21 16:28:42 +02:00
|
|
|
'warn'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2010-04-28 21:57:16 +02:00
|
|
|
$self->lmLog( "Logout response is valid", 'debug' );
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-04-28 21:57:16 +02:00
|
|
|
}
|
2010-04-26 19:06:49 +02:00
|
|
|
|
2010-04-28 19:16:38 +02:00
|
|
|
}
|
|
|
|
|
2010-04-26 19:06:49 +02:00
|
|
|
return ( 1, $method, $info );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-07-03 16:38:46 +02:00
|
|
|
## @pmethod int sendLogoutRequestToProviders(Lasso::Logout logout, string relayState )
|
|
|
|
# Send logout response issue from a logout request to all other
|
2010-05-05 09:10:13 +02:00
|
|
|
# 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
|
2010-06-21 18:24:50 +02:00
|
|
|
# @param relayState Relay State for SLO status
|
2010-05-05 09:10:13 +02:00
|
|
|
# @return int Number of concerned providers.
|
2010-07-03 16:38:46 +02:00
|
|
|
sub sendLogoutRequestToProviders {
|
2010-06-21 18:24:50 +02:00
|
|
|
my ( $self, $logout, $relayState ) = splice @_;
|
2010-05-05 09:10:13 +02:00
|
|
|
my $server = $self->{_lassoServer};
|
|
|
|
my $providersCount = 0;
|
|
|
|
my $info = '';
|
|
|
|
|
|
|
|
# Reset providerID into Lasso::Logout object
|
|
|
|
$self->resetProviderIdIndex($logout);
|
|
|
|
|
|
|
|
# Header of the block which will be displayed to the user, if needed.
|
2010-08-30 17:46:26 +02:00
|
|
|
$info .= '<h3>'
|
2010-06-16 18:17:05 +02:00
|
|
|
. &Lemonldap::NG::Portal::_i18n::msg
|
2010-05-12 06:04:10 +02:00
|
|
|
( Lemonldap::NG::Portal::Simple::PM_SAML_SPLOGOUT,
|
2010-05-05 09:10:13 +02:00
|
|
|
$ENV{HTTP_ACCEPT_LANGUAGE} )
|
2010-08-30 17:46:26 +02:00
|
|
|
. '</h3>'
|
2010-06-16 18:17:05 +02:00
|
|
|
. '<table class="sloState">';
|
2010-05-05 09:10:13 +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) ) {
|
|
|
|
|
|
|
|
# Send logout request
|
|
|
|
my ( $rstatus, $rmethod, $rinfo ) =
|
2010-07-03 16:38:46 +02:00
|
|
|
$self->sendLogoutRequestToProvider( $logout, $providerID, undef, 1,
|
|
|
|
$relayState );
|
2010-05-05 09:10:13 +02:00
|
|
|
|
|
|
|
next unless ($rstatus);
|
|
|
|
|
|
|
|
# Count providers that have to be request by HTTP redirect
|
|
|
|
$providersCount++;
|
|
|
|
|
|
|
|
# Add information if necessary
|
|
|
|
if ($rinfo) {
|
|
|
|
$info .= $rinfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
# End of information block to be displayed to the user.
|
2010-06-16 18:17:05 +02:00
|
|
|
$info .= '</table>';
|
2010-05-05 09:10:13 +02:00
|
|
|
|
2010-06-23 16:03:18 +02:00
|
|
|
# Print some information to the user.
|
|
|
|
$self->info($info) if $providersCount;
|
2010-05-05 09:10:13 +02:00
|
|
|
|
|
|
|
return $providersCount;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-05-03 23:12:14 +02:00
|
|
|
## @method boolean checkSignatureStatus(Lasso::Profile profile)
|
|
|
|
# Check signature status
|
|
|
|
# @param profile Lasso::Profile object
|
|
|
|
# @return result
|
|
|
|
sub checkSignatureStatus {
|
|
|
|
my ( $self, $profile ) = splice @_;
|
|
|
|
|
|
|
|
eval { Lasso::Profile::get_signature_status($profile); };
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
}
|
|
|
|
|
2010-05-12 17:14:07 +02:00
|
|
|
## @method int authnContext2authnLevel(string authnContext)
|
|
|
|
# Return authentication level corresponding to authnContext
|
|
|
|
# @param authnContext SAML authentication context
|
|
|
|
# return authentication level
|
|
|
|
sub authnContext2authnLevel {
|
|
|
|
my ( $self, $authnContext ) = splice @_;
|
|
|
|
|
2010-09-02 11:09:10 +02:00
|
|
|
return $self->{samlAuthnContextMapPassword}
|
|
|
|
if ( $authnContext eq $self->getAuthnContext("password") );
|
|
|
|
return $self->{samlAuthnContextMapPasswordProtectedTransport}
|
2010-05-12 17:14:07 +02:00
|
|
|
if (
|
|
|
|
$authnContext eq $self->getAuthnContext("password-protected-transport")
|
|
|
|
);
|
2010-09-02 11:09:10 +02:00
|
|
|
return $self->{samlAuthnContextMapKerberos}
|
|
|
|
if ( $authnContext eq $self->getAuthnContext("kerberos") );
|
|
|
|
return $self->{samlAuthnContextMapTLSClient}
|
|
|
|
if ( $authnContext eq $self->getAuthnContext("tls-client") );
|
2010-05-12 17:14:07 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method int authnLevel2authnContext(int authnLevel)
|
|
|
|
# Return SAML authentication context corresponding to authnLevel
|
|
|
|
# @param authnLevel internal authentication level
|
|
|
|
# return SAML authentication context
|
|
|
|
sub authnLevel2authnContext {
|
|
|
|
my ( $self, $authnLevel ) = splice @_;
|
|
|
|
|
2010-09-02 11:09:10 +02:00
|
|
|
return $self->getAuthnContext("password")
|
|
|
|
if ( $authnLevel == $self->{samlAuthnContextMapPassword} );
|
2010-05-12 17:14:07 +02:00
|
|
|
return $self->getAuthnContext("password-protected-transport")
|
2010-09-02 11:09:10 +02:00
|
|
|
if (
|
|
|
|
$authnLevel == $self->{samlAuthnContextMapPasswordProtectedTransport} );
|
|
|
|
return $self->getAuthnContext("kerberos")
|
|
|
|
if ( $authnLevel == $self->{samlAuthnContextMapKerberos} );
|
|
|
|
return $self->getAuthnContext("tls-client")
|
|
|
|
if ( $authnLevel == $self->{samlAuthnContextMapTLSClient} );
|
2010-05-12 17:14:07 +02:00
|
|
|
return $self->getAuthnContext("unspecified");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-05-21 15:44:16 +02:00
|
|
|
## @method boolean checkDestination(Lasso::Node message, string url)
|
|
|
|
# If SAML Destination attribute is present, check it
|
|
|
|
# @param message SAML request or response
|
|
|
|
# @param url Requested URL
|
|
|
|
# @return Result
|
|
|
|
sub checkDestination {
|
|
|
|
my ( $self, $message, $url ) = splice @_;
|
|
|
|
my $destination;
|
|
|
|
|
|
|
|
# Read Destination
|
|
|
|
eval { $destination = $message->Destination(); };
|
|
|
|
|
|
|
|
# Ok if no Destination
|
|
|
|
if ( $@ or !$destination ) {
|
|
|
|
$self->lmLog( "No Destination in SAML message", 'debug' );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "Destination $destination found in SAML message", 'debug' );
|
|
|
|
|
|
|
|
# Compare Destination and URL
|
|
|
|
if ( $destination =~ /^$url$/ ) {
|
|
|
|
$self->lmLog( "Destination match URL $url", 'debug' );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog( "Destination does not match URL $url", 'error' );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-02 11:04:07 +02:00
|
|
|
## @method hashref getSamlSession(string id)
|
|
|
|
# Try to recover the SAML session corresponding to id and return session datas
|
|
|
|
# If id is set to undef, return a new session
|
|
|
|
# @param id session reference
|
|
|
|
# @return session datas
|
|
|
|
sub getSamlSession {
|
|
|
|
my ( $self, $id ) = splice @_;
|
|
|
|
my %h;
|
|
|
|
|
|
|
|
# Trying to recover session from SAML session storage
|
|
|
|
eval { tie %h, $self->{samlStorage}, $id, $self->{samlStorageOptions}; };
|
|
|
|
if ( $@ or not tied(%h) ) {
|
|
|
|
|
|
|
|
# Session not available
|
|
|
|
if ($id) {
|
|
|
|
$self->lmLog( "SAML session $id isn't yet available", 'info' );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog( "Unable to create new SAML session: $@", 'error' );
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return \%h;
|
|
|
|
}
|
|
|
|
|
2010-06-04 16:23:41 +02:00
|
|
|
## @method Lasso::Saml2Attribute createAttribute(string name, string format, string friendly_name)
|
|
|
|
# Create a new SAML attribute
|
|
|
|
# @param name Attribute name
|
|
|
|
# @param format optional Attribute format
|
|
|
|
# @param friendly_name optional Attribute friendly name
|
|
|
|
# @return SAML attribute
|
|
|
|
sub createAttribute {
|
|
|
|
my ( $self, $name, $format, $friendly_name ) = splice @_;
|
|
|
|
my $attribute;
|
|
|
|
|
|
|
|
# Name is required
|
|
|
|
return unless defined $name;
|
|
|
|
|
|
|
|
# SAML2 attribute
|
|
|
|
eval { $attribute = Lasso::Saml2Attribute->new(); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# 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);
|
|
|
|
|
|
|
|
return $attribute;
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method Lasso::Saml2AttributeValue createAttributeValue(string value)
|
|
|
|
# Create a new SAML attribute value
|
|
|
|
# @param value Value to store
|
|
|
|
# @return SAML attribute value
|
|
|
|
sub createAttributeValue {
|
|
|
|
my ( $self, $value ) = splice @_;
|
|
|
|
my $saml2value;
|
|
|
|
|
|
|
|
# Value is required
|
|
|
|
return unless defined $value;
|
|
|
|
|
|
|
|
# SAML2 attribute value
|
|
|
|
eval { $saml2value = Lasso::Saml2AttributeValue->new(); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
my @any;
|
|
|
|
|
|
|
|
# Text node
|
|
|
|
my $textNode;
|
|
|
|
eval { $textNode = Lasso::MiscTextNode->new(); };
|
|
|
|
if ($@) {
|
|
|
|
$self->checkLassoError($@);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$textNode->text_child(1);
|
|
|
|
$textNode->content($value);
|
|
|
|
|
|
|
|
push @any, $textNode;
|
|
|
|
|
|
|
|
$saml2value->any(@any);
|
|
|
|
|
|
|
|
return $saml2value;
|
|
|
|
}
|
|
|
|
|
2010-06-04 17:54:52 +02:00
|
|
|
## @method int getEncryptionMode(string encryption_mode)
|
|
|
|
# Return Lasso encryption mode
|
|
|
|
# @param encryption_mode Encryption mode string
|
|
|
|
# @return Lasso encryption mode
|
|
|
|
sub getEncryptionMode {
|
|
|
|
my ( $self, $encryption_mode ) = splice @_;
|
|
|
|
|
|
|
|
return Lasso::Constants::ENCRYPTION_MODE_NAMEID
|
|
|
|
if ( $encryption_mode =~ /^nameid$/i );
|
|
|
|
return Lasso::Constants::ENCRYPTION_MODE_ASSERTION
|
|
|
|
if ( $encryption_mode =~ /^assertion$/i );
|
|
|
|
return Lasso::Constants::ENCRYPTION_MODE_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method boolean setProviderEncryptionMode(Lasso::Provider provider, int encryption_mode)
|
|
|
|
# Set encryption mode on a provider
|
|
|
|
# @param provider Lasso::Provider object
|
|
|
|
# @param encryption_mode Lasso encryption mode
|
|
|
|
# @return result
|
|
|
|
sub setProviderEncryptionMode {
|
|
|
|
my ( $self, $provider, $encryption_mode ) = splice @_;
|
|
|
|
|
|
|
|
eval {
|
|
|
|
Lasso::Provider::set_encryption_mode( $provider, $encryption_mode );
|
|
|
|
};
|
|
|
|
|
|
|
|
return $self->checkLassoError($@);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-06-11 16:13:26 +02:00
|
|
|
## @method boolean deleteSAMLSecondarySessions(string session_id)
|
|
|
|
# Find and delete SAML sessions bounded to a primary session
|
|
|
|
# @param session_id Primary session ID
|
|
|
|
# @return result
|
|
|
|
sub deleteSAMLSecondarySessions {
|
|
|
|
my ( $self, $session_id ) = splice @_;
|
|
|
|
my $result = 1;
|
|
|
|
|
|
|
|
# Find SAML sessions
|
|
|
|
my $saml_sessions =
|
|
|
|
$self->{samlStorage}
|
2010-08-31 16:36:45 +02:00
|
|
|
->searchOn( $self->{samlStorageOptions}, "_saml_id", $session_id );
|
2010-06-11 16:13:26 +02:00
|
|
|
|
|
|
|
if ( my @saml_sessions_keys = keys %$saml_sessions ) {
|
|
|
|
|
|
|
|
foreach my $saml_session (@saml_sessions_keys) {
|
|
|
|
|
|
|
|
# Get session
|
|
|
|
$self->lmLog( "Retrieve SAML session $saml_session", 'debug' );
|
|
|
|
|
|
|
|
my $samlSessionInfo = $self->getSamlSession($saml_session);
|
|
|
|
|
|
|
|
# Delete session
|
|
|
|
eval { tied(%$samlSessionInfo)->delete() };
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->lmLog( "Unable to delete SAML session $saml_session: $@",
|
|
|
|
'error' );
|
|
|
|
$result = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog( "SAML session $saml_session deleted", 'debug' );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->lmLog( "No SAML session found for session $session_id ",
|
|
|
|
'debug' );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2010-07-02 16:17:01 +02:00
|
|
|
## @method void sendSLOErrorResponse(Lasso::Logout logout, string method)
|
2010-06-28 10:34:15 +02:00
|
|
|
# Send an SLO error response
|
|
|
|
# @param logout Lasso::Logout object
|
|
|
|
# @param method HTTP method
|
2010-07-02 16:17:01 +02:00
|
|
|
# @return nothing
|
2010-06-28 10:34:15 +02:00
|
|
|
sub sendSLOErrorResponse {
|
|
|
|
my ( $self, $logout, $method ) = splice @_;
|
|
|
|
|
|
|
|
# Load empty session
|
|
|
|
my $session =
|
2010-07-03 15:55:43 +02:00
|
|
|
'<Session xmlns="http://www.entrouvert.org/namespaces/lasso/0.0"/>';
|
2010-06-28 10:34:15 +02:00
|
|
|
|
|
|
|
unless ( $self->setSessionFromDump( $logout, $session ) ) {
|
2010-07-02 16:17:01 +02:00
|
|
|
$self->lmLog( "Could not set empty session in logout object", 'error' );
|
|
|
|
$self->quit();
|
2010-06-28 10:34:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Send unvalidated SLO response
|
|
|
|
unless ( $self->sendLogoutResponseToServiceProvider( $logout, $method ) ) {
|
|
|
|
$self->lmLog( "Could not send SLO error response", 'error' );
|
2010-07-02 16:17:01 +02:00
|
|
|
$self->quit();
|
2010-06-28 10:34:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$self->lmLog( "SLO response error sent", 'debug' );
|
|
|
|
|
2010-07-02 16:17:01 +02:00
|
|
|
$self->quit();
|
2010-06-28 10:34:15 +02:00
|
|
|
}
|
|
|
|
|
2009-04-07 22:38:24 +02:00
|
|
|
1;
|
2010-01-29 18:33:35 +01:00
|
|
|
|
2009-04-07 22:38:24 +02:00
|
|
|
__END__
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
2010-01-03 09:09:59 +01:00
|
|
|
=encoding utf8
|
|
|
|
|
2010-03-25 09:55:42 +01:00
|
|
|
Lemonldap::NG::Portal::_SAML - Common SAML functions
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
2010-01-29 11:44:56 +01:00
|
|
|
use Lemonldap::NG::Portal::_SAML;
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
2010-01-29 11:44:56 +01:00
|
|
|
This module contains common methods for SAML authentication
|
|
|
|
and user information loading
|
|
|
|
|
|
|
|
=head1 METHODS
|
|
|
|
|
|
|
|
=head2 loadLasso
|
|
|
|
|
|
|
|
Load Lasso module
|
2009-04-07 22:38:24 +02:00
|
|
|
|
2010-03-26 10:35:31 +01:00
|
|
|
=head2 loadService
|
|
|
|
|
|
|
|
Load SAML service by creating a Lasso::Server
|
|
|
|
|
|
|
|
=head2 loadIDPs
|
|
|
|
|
|
|
|
Load SAML identity providers
|
|
|
|
|
|
|
|
=head2 loadSPs
|
|
|
|
|
|
|
|
Load SAML service providers
|
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
=head2 checkMessage
|
|
|
|
|
|
|
|
Check SAML requests and responses
|
|
|
|
|
2010-01-29 18:33:35 +01:00
|
|
|
=head2 checkLassoError
|
|
|
|
|
|
|
|
Log Lasso error code and message if this is actually a Lasso::Error with code > 0
|
|
|
|
|
|
|
|
=head2 createServer
|
|
|
|
|
|
|
|
Load service metadata and create Lasso::Server object
|
|
|
|
|
2010-02-01 18:07:40 +01:00
|
|
|
=head2 addIDP
|
|
|
|
|
|
|
|
Add IDP to an existing Lasso::Server
|
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
=head2 addSP
|
|
|
|
|
|
|
|
Add SP to an existing Lasso::Server
|
|
|
|
|
2010-06-01 14:23:11 +02:00
|
|
|
=head2 addAA
|
|
|
|
|
|
|
|
Add Attribute Authority to an existing Lasso::Server
|
|
|
|
|
2010-02-01 18:07:40 +01:00
|
|
|
=head2 addProvider
|
|
|
|
|
|
|
|
Add provider to an existing Lasso::Server
|
|
|
|
|
2010-02-05 18:18:09 +01:00
|
|
|
=head2 getOrganizationName
|
|
|
|
|
|
|
|
Return name of organization picked up from metadata
|
|
|
|
|
2010-02-04 17:02:02 +01:00
|
|
|
=head2 createAuthnRequest
|
|
|
|
|
|
|
|
Create authentication request for selected IDP
|
|
|
|
|
|
|
|
=head2 createLogin
|
|
|
|
|
|
|
|
Create Lasso::Login object
|
|
|
|
|
|
|
|
=head2 initAuthnRequest
|
|
|
|
|
|
|
|
Init authentication request
|
|
|
|
|
|
|
|
=head2 buildAuthnRequestMsg
|
|
|
|
|
|
|
|
Build authentication request message
|
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
=head2 processAuthnRequestMsg
|
|
|
|
|
|
|
|
Process authentication request message
|
|
|
|
|
|
|
|
=head2 validateRequestMsg
|
|
|
|
|
|
|
|
Validate request message
|
|
|
|
|
2010-04-07 17:14:17 +02:00
|
|
|
=head2 buildAuthnResponseMsg
|
|
|
|
|
|
|
|
Build authentication response message
|
|
|
|
|
|
|
|
=head2 buildArtifactMsg
|
|
|
|
|
|
|
|
Build artifact message
|
|
|
|
|
2010-04-07 18:37:23 +02:00
|
|
|
=head2 buildAssertion
|
|
|
|
|
|
|
|
Build assertion
|
|
|
|
|
2010-02-08 18:24:45 +01:00
|
|
|
=head2 processAuthnResponseMsg
|
|
|
|
|
|
|
|
Process authentication response message
|
|
|
|
|
2010-02-09 10:02:39 +01:00
|
|
|
=head2 getNameIdentifier
|
|
|
|
|
|
|
|
Get NameID from Lasso Profile
|
|
|
|
|
2010-02-11 13:39:42 +01:00
|
|
|
=head2 createIdentity
|
|
|
|
|
|
|
|
Create Lasso::Identity object
|
|
|
|
|
|
|
|
=head2 createSession
|
|
|
|
|
|
|
|
Create Lasso::Session object
|
|
|
|
|
|
|
|
=head2 acceptSSO
|
|
|
|
|
|
|
|
Accept SSO from IDP
|
|
|
|
|
2010-02-25 12:39:55 +01:00
|
|
|
=head2 storeRelayState
|
|
|
|
|
|
|
|
Store information in relayState database and return
|
|
|
|
|
2010-02-12 11:53:43 +01:00
|
|
|
=head2 extractRelayState
|
|
|
|
|
|
|
|
Extract RelayState information into $self
|
|
|
|
|
2010-02-12 15:26:45 +01:00
|
|
|
=head2 getAssertion
|
|
|
|
|
|
|
|
Get assertion in Lasso::Login object
|
|
|
|
|
|
|
|
=head2 getAttributeValue
|
|
|
|
|
|
|
|
Get SAML attribute value corresponding to name, format and friendly_name
|
|
|
|
Multivaluated values are separated by ';'
|
|
|
|
|
2010-02-15 18:03:07 +01:00
|
|
|
=head2 validateConditions
|
|
|
|
|
|
|
|
Validate conditions
|
|
|
|
|
2010-02-17 16:13:00 +01:00
|
|
|
=head2 createLogoutRequest
|
|
|
|
|
|
|
|
Create logout request for selected entity
|
|
|
|
|
|
|
|
=head2 createLogout
|
|
|
|
|
|
|
|
Create Lasso::Logout object
|
|
|
|
|
|
|
|
=head2 initLogoutRequest
|
|
|
|
|
|
|
|
Init logout request
|
|
|
|
|
|
|
|
=head2 buildLogoutRequestMsg
|
|
|
|
|
|
|
|
Build logout request message
|
|
|
|
|
2010-02-17 18:37:38 +01:00
|
|
|
=head2 setSessionFromDump
|
|
|
|
|
|
|
|
Set session from dump in Lasso::Profile object
|
|
|
|
|
2010-04-12 15:23:22 +02:00
|
|
|
=head2 setIdentityFromDump
|
|
|
|
|
|
|
|
Set identity from dump in Lasso::Profile object
|
|
|
|
|
2010-02-18 10:58:59 +01:00
|
|
|
=head2 getMetaDataURL
|
|
|
|
|
|
|
|
Get URL stored in a service metadata configuration key
|
|
|
|
|
2010-02-18 18:22:04 +01:00
|
|
|
=head2 processLogoutResponseMsg
|
|
|
|
|
|
|
|
Process logout response message
|
|
|
|
|
|
|
|
=head2 processLogoutRequestMsg
|
|
|
|
|
|
|
|
Process logout request message
|
|
|
|
|
2010-02-18 18:42:31 +01:00
|
|
|
=head2 validateLogoutRequest
|
|
|
|
|
|
|
|
Validate logout request
|
|
|
|
|
2010-02-19 12:33:34 +01:00
|
|
|
=head2 buildLogoutResponseMsg
|
|
|
|
|
|
|
|
Build logout response msg
|
|
|
|
|
2010-02-28 20:07:02 +01:00
|
|
|
=head2 storeReplayProtection
|
|
|
|
|
|
|
|
Store ID of an SAML message in Replay Protection base
|
|
|
|
|
2010-02-22 18:12:16 +01:00
|
|
|
=head2 replayProtection
|
|
|
|
|
|
|
|
Check if SAML message do not correspond to a previously responded message
|
|
|
|
|
2010-02-24 16:24:54 +01:00
|
|
|
=head2 resolveArtifact
|
|
|
|
|
|
|
|
Resolve artifact to get the real SAML message
|
|
|
|
|
2010-04-08 18:28:10 +02:00
|
|
|
=head2 storeArtifact
|
|
|
|
|
|
|
|
Store artifact
|
|
|
|
|
|
|
|
=head2 loadArtifact
|
|
|
|
|
|
|
|
Load artifact
|
|
|
|
|
2010-04-12 11:09:53 +02:00
|
|
|
=head2 createArtifactResponse
|
|
|
|
|
2010-05-21 15:44:16 +02:00
|
|
|
Create artifact response
|
2010-04-12 11:09:53 +02:00
|
|
|
|
2010-04-07 14:27:50 +02:00
|
|
|
=head2 processArtRequestMsg
|
|
|
|
|
|
|
|
Process artifact response message
|
|
|
|
|
2010-02-24 16:24:54 +01:00
|
|
|
=head2 processArtResponseMsg
|
|
|
|
|
|
|
|
Process artifact response message
|
|
|
|
|
2010-02-26 10:12:18 +01:00
|
|
|
=head2 sendSOAPMessage
|
|
|
|
|
|
|
|
Send SOAP message and get response
|
|
|
|
|
2010-06-01 17:34:08 +02:00
|
|
|
=head2 createAssertionQuery
|
|
|
|
|
|
|
|
Create a new assertion query
|
|
|
|
|
2010-03-03 17:54:23 +01:00
|
|
|
=head2 createAttributeRequest
|
|
|
|
|
|
|
|
Create an attribute request
|
|
|
|
|
2010-06-02 10:09:59 +02:00
|
|
|
=head2 validateAttributeRequest
|
|
|
|
|
|
|
|
Validate an attribute request
|
|
|
|
|
|
|
|
=head2 processAttributeRequest
|
|
|
|
|
|
|
|
Process an attribute request
|
|
|
|
|
2010-06-02 15:45:37 +02:00
|
|
|
=head2 buildAttributeResponse
|
|
|
|
|
|
|
|
Build attribute response
|
|
|
|
|
2010-03-03 17:54:23 +01:00
|
|
|
=head2 processAttributeResponse
|
|
|
|
|
|
|
|
Process an attribute response
|
|
|
|
|
2010-03-05 10:28:28 +01:00
|
|
|
=head2 getNameIDFormat
|
|
|
|
|
|
|
|
Convert configuration string into SAML2 NameIDFormat string
|
|
|
|
|
2010-03-05 17:57:11 +01:00
|
|
|
=head2 getHttpMethod
|
|
|
|
|
|
|
|
Convert configuration string into Lasso HTTP Method integer
|
|
|
|
|
2010-05-28 14:17:05 +02:00
|
|
|
=head2 getHttpMethodString
|
|
|
|
|
|
|
|
Convert configuration Lasso HTTP Method integer into string
|
|
|
|
|
2010-03-05 17:57:11 +01:00
|
|
|
=head2 getFirstHttpMethod
|
|
|
|
|
|
|
|
Find a suitable HTTP method for an entity with a given protocol
|
|
|
|
|
2010-04-01 14:51:32 +02:00
|
|
|
=head2 disableSignature
|
|
|
|
|
|
|
|
Modify Lasso signature hint to disable signature
|
|
|
|
|
2010-04-01 16:18:37 +02:00
|
|
|
=head2 forceSignature
|
|
|
|
|
|
|
|
Modify Lasso signature hint to force signature
|
|
|
|
|
2010-04-16 12:13:20 +02:00
|
|
|
=head2 disableSignatureVerification
|
|
|
|
|
|
|
|
Modify Lasso signature hint to disable signature verification
|
|
|
|
|
2010-04-01 18:32:51 +02:00
|
|
|
=head2 getAuthnContext
|
|
|
|
|
|
|
|
Convert configuration string into SAML2 AuthnContextClassRef string
|
|
|
|
|
2010-04-08 11:39:53 +02:00
|
|
|
=head2 timestamp2samldate
|
|
|
|
|
|
|
|
Convert timestamp into SAML2 date format
|
|
|
|
|
|
|
|
=head2 samldate2timestamp
|
|
|
|
|
|
|
|
Convert SAML2 date format into timestamp
|
|
|
|
|
2010-04-28 16:29:52 +02:00
|
|
|
=head2 sendLogoutResponseToServiceProvider
|
|
|
|
|
|
|
|
Send logout response issue from a logout request
|
|
|
|
|
2010-07-03 16:38:46 +02:00
|
|
|
=head2 sendLogoutRequestToProvider
|
2010-04-28 16:29:52 +02:00
|
|
|
|
2010-07-03 16:38:46 +02:00
|
|
|
Send logout request to a provider
|
2010-04-28 16:29:52 +02:00
|
|
|
|
2010-07-03 16:38:46 +02:00
|
|
|
=head2 sendLogoutRequestToProviders
|
2010-05-05 09:10:13 +02:00
|
|
|
|
2010-07-03 16:38:46 +02:00
|
|
|
Send logout response issue from a logout request to all other
|
2010-05-05 09:10:13 +02:00
|
|
|
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.
|
|
|
|
|
2010-05-03 23:12:14 +02:00
|
|
|
=head2 checkSignatureStatus
|
|
|
|
|
|
|
|
Check signature status
|
|
|
|
|
2010-05-12 17:14:07 +02:00
|
|
|
=head2 authnContext2authnLevel
|
|
|
|
|
|
|
|
Return authentication level corresponding to authnContext
|
|
|
|
|
|
|
|
=head2 authnLevel2authnContext
|
|
|
|
|
|
|
|
Return SAML authentication context corresponding to authnLevel
|
|
|
|
|
2010-05-21 15:44:16 +02:00
|
|
|
=head2 checkDestination
|
|
|
|
|
|
|
|
If SAML Destination attribute is present, check it
|
|
|
|
|
2010-06-02 11:04:07 +02:00
|
|
|
=head2 getSamlSession
|
|
|
|
|
|
|
|
Try to recover the SAML session corresponding to id and return session datas
|
|
|
|
|
2010-06-04 16:23:41 +02:00
|
|
|
=head2 createAttribute
|
|
|
|
|
|
|
|
Create a new SAML attribute
|
|
|
|
|
|
|
|
=head2 createAttributeValue
|
|
|
|
|
|
|
|
Create a new SAML attribute value
|
|
|
|
|
2010-06-04 17:54:52 +02:00
|
|
|
=head2 getEncryptionMode
|
|
|
|
|
|
|
|
Return Lasso encryption mode
|
|
|
|
|
|
|
|
=head2 setProviderEncryptionMode
|
|
|
|
|
|
|
|
Set encryption mode on a provider
|
|
|
|
|
2010-06-11 16:13:26 +02:00
|
|
|
=head2 deleteSAMLSecondarySessions
|
|
|
|
|
|
|
|
Find and delete SAML sessions bounded to a primary session
|
|
|
|
|
2010-06-28 10:34:15 +02:00
|
|
|
=head2 sendSLOErrorResponse
|
|
|
|
|
|
|
|
Send an SLO error response
|
|
|
|
|
2009-04-07 22:38:24 +02:00
|
|
|
=head1 SEE ALSO
|
|
|
|
|
2010-01-29 11:44:56 +01:00
|
|
|
L<Lemonldap::NG::Portal::AuthSAML>, L<Lemonldap::NG::Portal::UserDBSAML>
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
2010-01-29 11:44:56 +01:00
|
|
|
Xavier Guimard, E<lt>x.guimard@free.frE<gt>,
|
|
|
|
Clement Oudot, E<lt>coudot@linagora.comE<gt>
|
2009-04-07 22:38:24 +02:00
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
|
2010-01-29 11:44:56 +01:00
|
|
|
Copyright (C) 2009 by Xavier Guimard, Clement 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
|