Lemonldap-NG-Portal
view release on metacpan or search on metacpan
lib/Lemonldap/NG/Portal/Lib/SAML.pm view on Meta::CPAN
$moduleOptions->{backend} = $self->conf->{samlStorage};
}
else {
$moduleOptions = $self->conf->{globalStorageOptions} || {};
$moduleOptions->{backend} = $self->conf->{globalStorage};
}
$self->aModule( $moduleOptions->{backend} );
$self->amOpts($moduleOptions);
# Check for Lasso errors/messages (see BEGIN)
unless (LASSO) {
$self->logger->error("Module Lasso not loaded (see below)");
return 0;
}
if (BADLASSO) {
$self->logger->error('Lasso version >= 2.3.0 required');
return 0;
}
unless (LASSOTHINSESSIONS) {
$self->logger->warn('Lasso thin-sessions flag could not be set');
}
else {
$self->logger->debug('Lasso thin-sessions flag set');
}
if (GLIB) {
Glib::Log->set_handler(
"Lasso",
[qw/ error critical warning message info debug /],
sub {
$self->logger->debug(
$_[0] . " error " . $_[1] . ": " . $_[2] );
}
);
}
# Conf initialization
return 0 unless ( $self->lassoServer( $self->loadService ) );
$self->addUnauthRoute(
( $self->{path} || 'saml' ) =>
{ 'metadata' => { ':type' => 'metadata' } },
['GET']
);
$self->addAuthRoute(
( $self->{path} || 'saml' ) =>
{ 'metadata' => { ':type' => 'metadata' } },
['GET']
);
return 1;
}
# METHODS
sub loadService {
my ($self) = @_;
# Check if certificate is available
my $signing_key =
$self->get_private_key( $self->_get_default_signing_key_name );
unless ($signing_key) {
$self->logger->error(
'SAML private and public key not found in configuration');
return 0;
}
my $serviceCertificate;
if ( $self->conf->{samlServiceUseCertificateInResponse}
and $signing_key->{public} =~ /CERTIFICATE/ )
{
$serviceCertificate = $signing_key->{public};
$self->logger->debug('Certificate will be used in SAML responses');
}
# Get metadata from configuration
$self->logger->debug("Get Metadata for this service");
my $metadata = $self->_get_metadata_xml( undef, "all" );
$self->logger->debug("Create Lasso server");
my $encryption_key =
$self->get_private_key( $self->_get_default_encryption_key_name );
# Create Lasso server with service metadata
my $server = $self->createServer(
$metadata,
$signing_key->{private},
$signing_key->{password},
# use signature cert for encryption unless defined
(
$encryption_key
? ( $encryption_key->{private}, $encryption_key->{password}, )
: ( $signing_key->{private}, $signing_key->{password}, )
),
$serviceCertificate
);
unless ($server) {
$self->logger->error('Unable to create Lasso server');
return 0;
}
# Signature method
my $method = $self->getDefaultSignatureMethod();
$server->signature_method( $self->getSignatureMethod($method) );
$self->logger->debug("Set $method as SAML server signature method ");
# Log
$self->logger->debug("Service created");
return $server;
}
sub loadIDPs {
my ($self) = @_;
# 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
foreach ( keys %{ $self->conf->{samlIDPMetaDataXML} } ) {
$self->loadIDP($_);
}
return 1;
}
sub loadIDP {
my ( $self, $idpConfKey ) = @_;
$self->logger->debug("Get Metadata for IDP $idpConfKey");
# If XML metadata has been set in conf, load this provider from conf
my $idp_metadata =
$self->conf->{samlIDPMetaDataXML}->{$idpConfKey}->{samlIDPMetaDataXML};
if ($idp_metadata) {
if ( $self->load_idp_from_conf( $idpConfKey, $idp_metadata ) ) {
$self->logger->debug("IDP $idpConfKey added");
}
else {
$self->logger->warn("Ignoring IDP $idpConfKey");
}
lib/Lemonldap/NG/Portal/Lib/SAML.pm view on Meta::CPAN
my $type = eval {
my $resp = Lasso::Samlp2ArtifactResponse->new;
$resp->init_from_message($message);
$resp->any->get_name;
};
if ($@) {
$self->logger->warn("Could not detect type of Artifact response");
return;
}
$self->logger->debug("Artifact response type is $type");
if ( $type eq "Response" ) {
return 1;
}
else {
return 0;
}
}
## @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 error Lasso error object
# @param level optional log level (debug by default)
# @return 1 if no error
sub checkLassoError {
my ( $self, $error, $level ) = @_;
my ( $lasso_result, $lasso_error_code ) =
$self->getLassoError( $error, $level );
return $lasso_result;
}
## @method boolean getLassoError(Lasso::Error error, string level)
# Log Lasso error code and message if this is actually a Lasso::Error with code > 0
# @param error Lasso error object
# @param level optional log level (debug by default)
# @return (success status, lasso error code)
sub getLassoError {
my ( $self, $error, $level ) = @_;
$level ||= 'error';
# If $error is not a Lasso::Error object, display error string
unless ( ref($error) and $error->isa("Lasso::Error") ) {
return ( 1, undef ) unless $error;
$self->p->lmLog( "Lasso error: $error", $level );
return ( 0, undef );
}
# Else check error code and error message
if ( $error->{code} ) {
$self->p->lmLog(
"Lasso error code " . $error->{code} . ": " . $error->{message},
$level );
return ( 0, $error->{code} );
}
return ( 1, undef );
}
## @method Lasso::Server createServer(string metadata, string private_key, string private_key_password, string private_key_enc, string private_key_enc_password, string certificate)
# Load service metadata and create Lasso::Server object
# @param metadata SAML metadata
# @param private_key private key
# @param private_key_password optional private key password
# @param private_key_enc optional private key for encryption
# @param private_key_enc_password optional private key password for encryption
# @param certificate optional certificate
# @return Lasso::Server object
sub createServer {
my ( $self, $metadata, $private_key, $private_key_password,
$private_key_enc, $private_key_enc_password, $certificate )
= @_;
my $server;
# https://dev.entrouvert.org/issues/51415
my $save_env = $ENV{'SSL_CERT_FILE'};
$ENV{'SSL_CERT_FILE'} = "/dev/null";
eval {
$server = Lasso::Server::new_from_buffers( $metadata, $private_key,
$private_key_password, $certificate );
# Set private key for encryption
if ( $server && $private_key_enc ) {
Lasso::Server::set_encryption_private_key_with_password( $server,
$private_key_enc, $private_key_enc_password );
}
};
if ( defined $save_env ) {
$ENV{'SSL_CERT_FILE'} = $save_env;
}
else {
delete $ENV{'SSL_CERT_FILE'};
}
if ($@) {
$self->checkLassoError($@);
return;
}
return $server;
}
## @method boolean addIDP(Lasso::Server server, string metadata, string public_key, string ca_cert_chain)
# Add IDP to an existing Lasso::Server
# @param server Lasso::Server object
# @param metadata IDP metadata
# @param public_key optional public key
# @param ca_cert_chain optional ca cert chain
# @return boolean result
sub addIDP {
my ( $self, $server, $metadata, $public_key, $ca_cert_chain ) = @_;
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 );
}
## @method boolean addSP(Lasso::Server server, string metadata, string public_key, string ca_cert_chain)
# Add SP to an existing Lasso::Server
# @param server Lasso::Server object
# @param metadata SP metadata
# @param public_key optional public key
# @param ca_cert_chain optional ca cert chain
# @return boolean result
sub addSP {
my ( $self, $server, $metadata, $public_key, $ca_cert_chain ) = @_;
return 0 unless ( $server->isa("Lasso::Server") and defined $metadata );
return $self->addProvider( $server, Lasso::Constants::PROVIDER_ROLE_SP,
$metadata, $public_key, $ca_cert_chain );
}
## @method boolean addAA(Lasso::Server server, string metadata, string public_key, string ca_cert_chain)
# Add Attribute Authority to an existing Lasso::Server
# @param server Lasso::Server object
# @param metadata AA metadata
# @param public_key optional public key
# @param ca_cert_chain optional ca cert chain
# @return boolean result
sub addAA {
my ( $self, $server, $metadata, $public_key, $ca_cert_chain ) = @_;
lib/Lemonldap/NG/Portal/Lib/SAML.pm view on Meta::CPAN
for my $key_id ( split( /\s*,\s*/, $list_of_keys ) ) {
my $key = $self->get_public_key($key_id);
if ($key) {
push @keys, $key;
}
else {
$self->logger->debug("Could not publish $key_id in metadata");
}
}
}
return @keys;
}
sub metadata {
my ( $self, $req ) = @_;
my $type = $req->param('type') || 'all';
my $idp = $req->param('idp');
my $sp = $req->param('sp');
if ( my $metadata = $self->_get_metadata_xml( $req, $type, $sp, $idp ) ) {
return $self->p->sendTextResponse( $req, $metadata,
type => 'application/xml' );
}
return $self->p->sendError( $req, 'Unable to build Metadata', 500 );
}
## @method int getSignatureMethod(string signature_method)
# Return Lasso signature method
# @param signature_method Signature method string
# @return Lasso signature method
sub getSignatureMethod {
my ( $self, $signature_method ) = @_;
$signature_method ||= $self->getDefaultSignatureMethod();
if ( my $const =
Lasso::Constants->can( "SIGNATURE_METHOD_" . uc($signature_method) ) )
{
return $const->();
}
else {
return 0;
}
}
sub getDefaultSignatureMethod {
my ($self) = @_;
my $signature_method =
$self->conf->{samlServiceSignatureMethod} || 'RSA_SHA1';
return $signature_method;
}
## @method boolean setProviderSignatureMethod(Lasso::Provider provider, int signature_method)
# Set signature method on a provider
# @param provider Lasso::Provider object
# @param signature_method Lasso signature method
# @return result
sub setProviderSignatureMethod {
my ( $self, $provider, $signature_method ) = @_;
my $key = $self->get_private_key( $self->_get_default_signing_key_name );
return $self->setProviderSignatureOptions( $provider, $signature_method,
$key );
}
sub setProviderSignatureOptions {
my ( $self, $provider, $signature_method, $key ) = @_;
# We have to use an intermediate variable to avoid interferences between
# Lasso binding and tied hashes (#3105)
my $priv = $key->{private};
my $pass = $key->{password};
my $cert = $key->{public};
eval {
my $key = Lasso::Key::new_for_signature_from_file( $priv, $pass,
$signature_method, $cert, );
$provider->set_server_signing_key($key);
};
return $self->checkLassoError($@);
}
sub _override_signature_or_key {
my ( $self, $entityID, $log_description, $signature_method,
$signature_key_list )
= @_;
if ( $signature_method or $signature_key_list ) {
$signature_key_list //= "";
my $signature_key = ( split( /\s*,\s*/, $signature_key_list ) )[0];
$signature_method ||= $self->getDefaultSignatureMethod;
my $lasso_signature_method =
$self->getSignatureMethod($signature_method);
$signature_key ||= $self->_get_default_signing_key_name;
my $key = $self->get_private_key($signature_key);
# Fallback to default key if custom key was not found
if ( !$key ) {
$signature_key = $self->_get_default_signing_key_name;
$key = $self->get_private_key($signature_key);
}
$self->logger->debug( "Setting signature key $signature_key"
. " and signature method $signature_method"
. " on $log_description" );
unless (
$self->setProviderSignatureOptions(
$self->lassoServer->get_provider($entityID),
$lasso_signature_method, $key
)
)
{
$self->logger->error(
"Unable to set signature options on $log_description");
return;
}
}
}
# The default signing key is the first key listed in samlServiceSignatureKey, with
# fallback to default-saml-sig
sub _get_default_signing_key_name {
my ($self) = @_;
my @key_list =
split( /\s*,\s*/, ( $self->conf->{samlServiceSignatureKey} || "" ) );
return ( $key_list[0] || "default-saml-sig" );
}
# The default encryption key is the first key listed in samlServiceEncryptionKey, with
# fallback to default-saml-enc
sub _get_default_encryption_key_name {
my ($self) = @_;
my @key_list =
split( /\s*,\s*/, ( $self->conf->{samlServiceEncryptionKey} || "" ) );
return ( $key_list[0] || "default-saml-enc" );
}
1;
__END__
=head1 NAME
=encoding utf8
Lemonldap::NG::Portal::Lib::SAML - Common SAML functions
=head1 SYNOPSIS
use Lemonldap::NG::Portal::Lib::SAML;
=head1 DESCRIPTION
This module contains common methods for SAML authentication
and user information loading
=head1 METHODS
( run in 0.803 second using v1.01-cache-2.11-cpan-13bb782fe5a )