2016-11-15 22:00:29 +01:00
|
|
|
package Lemonldap::NG::Portal::UserDB::SAML;
|
|
|
|
|
|
|
|
use strict;
|
2016-11-30 13:44:12 +01:00
|
|
|
use Encode;
|
2016-11-15 22:00:29 +01:00
|
|
|
use Mouse;
|
|
|
|
use Lemonldap::NG::Portal::Main::Constants qw(
|
|
|
|
PE_OK
|
2016-11-15 22:24:13 +01:00
|
|
|
PE_SAML_ATTR_ERROR
|
|
|
|
PE_SAML_LOAD_IDP_ERROR
|
|
|
|
PE_SAML_LOAD_SERVICE_ERROR
|
2016-11-15 22:00:29 +01:00
|
|
|
);
|
|
|
|
|
2019-05-29 23:50:39 +02:00
|
|
|
our $VERSION = '2.0.5';
|
2016-11-15 22:00:29 +01:00
|
|
|
|
|
|
|
extends 'Lemonldap::NG::Common::Module', 'Lemonldap::NG::Portal::Lib::SAML';
|
|
|
|
|
|
|
|
# INITIALIZATION
|
|
|
|
|
|
|
|
sub init {
|
|
|
|
my ($self) = @_;
|
|
|
|
|
2016-11-16 11:30:32 +01:00
|
|
|
# SAML service has been already loaded
|
2016-12-26 10:23:35 +01:00
|
|
|
$self->lassoServer(
|
|
|
|
$self->p->loadedModules->{'Lemonldap::NG::Portal::Auth::SAML'}
|
|
|
|
->lassoServer );
|
2016-11-16 11:30:32 +01:00
|
|
|
return 1;
|
2016-11-15 22:00:29 +01:00
|
|
|
}
|
|
|
|
|
2016-12-20 12:53:33 +01:00
|
|
|
# RUNNING METHODS
|
2016-11-15 22:24:13 +01:00
|
|
|
|
|
|
|
# Does nothing
|
|
|
|
sub getUser {
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2020-12-22 15:17:23 +01:00
|
|
|
sub findUser {
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2016-11-15 22:24:13 +01:00
|
|
|
# Get all required attributes
|
|
|
|
sub setSessionInfo {
|
|
|
|
my ( $self, $req ) = @_;
|
2018-07-05 22:56:16 +02:00
|
|
|
my $idp = $req->data->{_idp};
|
|
|
|
my $idpConfKey = $req->data->{_idpConfKey};
|
|
|
|
my $nameid = $req->data->{_nameID};
|
2016-11-15 22:24:13 +01:00
|
|
|
|
|
|
|
my $exportedAttr;
|
|
|
|
|
|
|
|
# Force UTF-8
|
2019-05-29 23:50:39 +02:00
|
|
|
my $force_utf8 =
|
|
|
|
$self->conf->{samlIDPMetaDataOptions}->{$idpConfKey}
|
|
|
|
->{samlIDPMetaDataOptionsForceUTF8}
|
|
|
|
if $idpConfKey;
|
2016-11-15 22:24:13 +01:00
|
|
|
|
|
|
|
# Get all required attributes, not already set
|
|
|
|
# in setAuthSessionInfo()
|
2019-05-29 23:50:39 +02:00
|
|
|
if ($idpConfKey) {
|
|
|
|
foreach (
|
|
|
|
keys
|
|
|
|
%{ $self->conf->{samlIDPMetaDataExportedAttributes}->{$idpConfKey} }
|
|
|
|
)
|
|
|
|
{
|
2016-11-15 22:24:13 +01:00
|
|
|
|
2019-05-29 23:50:39 +02:00
|
|
|
# Extract fields from exportedAttr value
|
|
|
|
my ( $mandatory, $name, $format, $friendly_name ) =
|
|
|
|
split( /;/,
|
|
|
|
$self->conf->{samlIDPMetaDataExportedAttributes}->{$idpConfKey}
|
|
|
|
->{$_} );
|
2016-11-15 22:24:13 +01:00
|
|
|
|
2019-05-29 23:50:39 +02:00
|
|
|
# Keep mandatory attributes not sent in authentication response
|
|
|
|
if ( $mandatory and not defined $req->{sessionInfo}->{$_} ) {
|
|
|
|
$exportedAttr->{$_} =
|
|
|
|
$self->conf->{samlIDPMetaDataExportedAttributes}
|
|
|
|
->{$idpConfKey}->{$_};
|
|
|
|
$self->logger->debug(
|
|
|
|
"Attribute $_ will be requested to $idpConfKey");
|
|
|
|
}
|
2016-11-15 22:24:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unless ( keys %$exportedAttr ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug(
|
|
|
|
"All mandatory attributes were present in authentication response");
|
2016-11-15 22:24:13 +01:00
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Save current Lasso::Server object, and get a new one
|
|
|
|
my $current_server = $self->lassoServer;
|
|
|
|
$self->loadService(1);
|
|
|
|
my $server = $self->lassoServer;
|
|
|
|
|
|
|
|
unless ($server) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error('Unable to create service for attribute request');
|
2016-11-15 22:24:13 +01:00
|
|
|
return PE_SAML_LOAD_SERVICE_ERROR;
|
|
|
|
}
|
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Service for attribute request created");
|
2016-11-15 22:24:13 +01:00
|
|
|
|
|
|
|
# Add current IDP as Attribute Authority
|
|
|
|
my $idp_metadata =
|
|
|
|
$self->conf->{samlIDPMetaDataXML}->{$idpConfKey}->{samlIDPMetaDataXML};
|
|
|
|
|
|
|
|
if ( $self->conf->{samlMetadataForceUTF8} ) {
|
|
|
|
$idp_metadata = encode( "utf8", $idp_metadata );
|
|
|
|
}
|
|
|
|
|
|
|
|
# Add this IDP to Lasso::Server as AA
|
|
|
|
unless ( $self->addAA( $server, $idp_metadata ) ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error(
|
|
|
|
"Fail to use IDP $idpConfKey Metadata as Attribute Authority");
|
2016-11-15 22:24:13 +01:00
|
|
|
return PE_SAML_LOAD_IDP_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Build Attribute Request
|
|
|
|
my $query =
|
|
|
|
$self->createAttributeRequest( $server, $idp, $exportedAttr, $nameid );
|
|
|
|
|
|
|
|
unless ($query) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error(
|
|
|
|
"Unable to build attribute request for $idpConfKey");
|
2016-11-15 22:24:13 +01:00
|
|
|
return PE_SAML_ATTR_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Use SOAP to send request and get response
|
|
|
|
my $query_url = $query->msg_url;
|
|
|
|
my $query_body = $query->msg_body;
|
|
|
|
|
|
|
|
# Send SOAP request and manage response
|
|
|
|
my $response = $self->sendSOAPMessage( $query_url, $query_body );
|
|
|
|
|
|
|
|
unless ($response) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error("No attribute response to SOAP request");
|
2016-11-15 22:24:13 +01:00
|
|
|
return PE_SAML_ATTR_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Manage Attribute Response
|
|
|
|
my $result = $self->processAttributeResponse( $server, $response );
|
|
|
|
|
|
|
|
unless ($result) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error("Fail to process attribute response");
|
2016-11-15 22:24:13 +01:00
|
|
|
return PE_SAML_ATTR_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Attributes in response
|
|
|
|
my @response_attributes;
|
|
|
|
eval {
|
|
|
|
@response_attributes =
|
|
|
|
$result->response()->Assertion()->AttributeStatement()->Attribute();
|
|
|
|
};
|
|
|
|
if ($@) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error("No attributes defined in attribute response");
|
2016-11-15 22:24:13 +01:00
|
|
|
return PE_SAML_ATTR_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Check we have all required attributes
|
|
|
|
foreach ( keys %$exportedAttr ) {
|
|
|
|
|
|
|
|
# Extract fields from exportedAttr value
|
|
|
|
my ( $mandatory, $name, $format, $friendly_name ) =
|
|
|
|
split( /;/, $exportedAttr->{$_} );
|
|
|
|
|
|
|
|
# Try to get value
|
|
|
|
my $value = $self->getAttributeValue( $name, $format, $friendly_name,
|
|
|
|
\@response_attributes, $force_utf8 );
|
|
|
|
|
|
|
|
unless ($value) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error(
|
|
|
|
"Attribute $_ is mandatory, but was not delivered by $idpConfKey"
|
2016-11-15 22:24:13 +01:00
|
|
|
);
|
|
|
|
return PE_SAML_ATTR_ERROR;
|
|
|
|
}
|
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Get value $value for attribute $_");
|
2016-11-15 22:24:13 +01:00
|
|
|
|
|
|
|
# Store value in sessionInfo
|
|
|
|
$req->{sessionInfo}->{$_} = $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Restore current Lasso::Server
|
|
|
|
$self->lassoServer = $current_server;
|
|
|
|
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Does nothing
|
|
|
|
sub setGroups {
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2016-11-15 22:00:29 +01:00
|
|
|
1;
|