lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/SAML.pm
Christophe Maudoux c0db322ef0 Perl critic
2021-04-01 23:07:58 +02:00

195 lines
5.1 KiB
Perl

package Lemonldap::NG::Portal::UserDB::SAML;
use strict;
use Encode;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK
PE_SAML_ATTR_ERROR
PE_SAML_LOAD_IDP_ERROR
PE_SAML_LOAD_SERVICE_ERROR
);
our $VERSION = '2.0.12';
extends qw(
Lemonldap::NG::Common::Module
Lemonldap::NG::Portal::Lib::SAML
);
# INITIALIZATION
sub init {
my ($self) = @_;
# SAML service has been already loaded
$self->lassoServer(
$self->p->loadedModules->{'Lemonldap::NG::Portal::Auth::SAML'}
->lassoServer );
return 1;
}
# RUNNING METHODS
# Does nothing
sub getUser {
return PE_OK;
}
sub findUser {
return PE_OK;
}
# Get all required attributes
sub setSessionInfo {
my ( $self, $req ) = @_;
my $idp = $req->data->{_idp};
my $idpConfKey = $req->data->{_idpConfKey};
my $nameid = $req->data->{_nameID};
my $exportedAttr;
# Force UTF-8
my $force_utf8 =
$self->conf->{samlIDPMetaDataOptions}->{$idpConfKey}
->{samlIDPMetaDataOptionsForceUTF8}
if $idpConfKey;
# Get all required attributes, not already set
# in setAuthSessionInfo()
if ($idpConfKey) {
foreach (
keys
%{ $self->conf->{samlIDPMetaDataExportedAttributes}->{$idpConfKey} }
)
{
# Extract fields from exportedAttr value
my ( $mandatory, $name, $format, $friendly_name ) =
split( /;/,
$self->conf->{samlIDPMetaDataExportedAttributes}->{$idpConfKey}
->{$_} );
# 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");
}
}
}
unless ( keys %$exportedAttr ) {
$self->logger->debug(
"All mandatory attributes were present in authentication response");
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) {
$self->logger->error('Unable to create service for attribute request');
return PE_SAML_LOAD_SERVICE_ERROR;
}
$self->logger->debug("Service for attribute request created");
# 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 ) ) {
$self->logger->error(
"Fail to use IDP $idpConfKey Metadata as Attribute Authority");
return PE_SAML_LOAD_IDP_ERROR;
}
# Build Attribute Request
my $query =
$self->createAttributeRequest( $server, $idp, $exportedAttr, $nameid );
unless ($query) {
$self->logger->error(
"Unable to build attribute request for $idpConfKey");
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) {
$self->logger->error("No attribute response to SOAP request");
return PE_SAML_ATTR_ERROR;
}
# Manage Attribute Response
my $result = $self->processAttributeResponse( $server, $response );
unless ($result) {
$self->logger->error("Fail to process attribute response");
return PE_SAML_ATTR_ERROR;
}
# Attributes in response
my @response_attributes;
eval {
@response_attributes =
$result->response()->Assertion()->AttributeStatement()->Attribute();
};
if ($@) {
$self->logger->error("No attributes defined in attribute response");
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) {
$self->logger->error(
"Attribute $_ is mandatory, but was not delivered by $idpConfKey"
);
return PE_SAML_ATTR_ERROR;
}
$self->logger->debug("Get value $value for attribute $_");
# Store value in sessionInfo
$req->{sessionInfo}->{$_} = $value;
}
# Restore current Lasso::Server
$self->lassoServer = $current_server;
return PE_OK;
}
# Does nothing
sub setGroups {
return PE_OK;
}
1;