2010-09-10 21:52:44 +02:00
|
|
|
## @file
|
|
|
|
# Common functions for authentication choice
|
|
|
|
|
|
|
|
## @class
|
|
|
|
# Common functions for authentication choice
|
|
|
|
|
|
|
|
package Lemonldap::NG::Portal::_Choice;
|
|
|
|
|
|
|
|
use Lemonldap::NG::Portal::Simple;
|
2014-06-05 20:05:55 +02:00
|
|
|
use Scalar::Util 'weaken';
|
2010-09-10 21:52:44 +02:00
|
|
|
|
2014-06-06 12:04:14 +02:00
|
|
|
our $VERSION = '1.4.0';
|
2010-09-10 21:52:44 +02:00
|
|
|
|
|
|
|
## @cmethod Lemonldap::NG::Portal::_Choice new(Lemonldap::NG::Portal::Simple portal)
|
|
|
|
# Constructor
|
|
|
|
# @param $portal Lemonldap::NG::Portal::Simple object
|
|
|
|
# @return new Lemonldap::NG::Portal::_Choice object
|
|
|
|
sub new {
|
2016-01-02 10:29:05 +01:00
|
|
|
my ( $class, $portal ) = @_;
|
2010-09-10 21:52:44 +02:00
|
|
|
|
|
|
|
# Create object with portal parameter
|
|
|
|
my $self = bless { p => $portal }, $class;
|
2014-06-05 20:05:55 +02:00
|
|
|
weaken $self->{p};
|
2010-09-10 21:52:44 +02:00
|
|
|
|
2010-09-13 17:14:19 +02:00
|
|
|
# Recover authChoice from session
|
|
|
|
$portal->{_authChoice} ||= $portal->{sessionInfo}->{_authChoice};
|
|
|
|
|
2010-09-10 21:52:44 +02:00
|
|
|
# Test authChoice
|
|
|
|
unless ( $portal->{_authChoice}
|
|
|
|
and exists $portal->{authChoiceModules}->{ $portal->{_authChoice} } )
|
|
|
|
{
|
|
|
|
$portal->lmLog( "No authentication choice done, or wrong choice",
|
|
|
|
'debug' );
|
|
|
|
$portal->{_authChoice} = "";
|
|
|
|
}
|
|
|
|
|
2013-11-06 17:33:26 +01:00
|
|
|
# Special workaround for Captcha
|
|
|
|
# Init Captcha to have it displayed even if no choice already done
|
|
|
|
if ( $portal->{captcha_login_enabled} ) {
|
|
|
|
eval { $portal->initCaptcha(); };
|
|
|
|
$portal->lmLog( "Can't init captcha: $@", "error" ) if $@;
|
|
|
|
}
|
|
|
|
|
2010-09-10 21:52:44 +02:00
|
|
|
# Special workaround for SAML
|
|
|
|
# because we cannot easily set SSO return URL
|
|
|
|
# and SLO URL with authChoice parameter
|
|
|
|
|
|
|
|
# Test authForce to see if URL is an SAML URL
|
|
|
|
unless ( $portal->{_authChoice} ) {
|
|
|
|
my $samlModule = 'Lemonldap::NG::Portal::AuthSAML';
|
|
|
|
my $samlForce = 0;
|
|
|
|
eval {
|
2013-10-01 14:50:48 +02:00
|
|
|
$portal->loadModule( $samlModule, 1 );
|
2010-09-10 21:52:44 +02:00
|
|
|
$authForce = $samlModule . '::authForce';
|
|
|
|
$samlForce = $portal->$authForce;
|
|
|
|
};
|
|
|
|
|
2010-09-23 18:41:39 +02:00
|
|
|
if ($@) {
|
2010-09-13 17:14:19 +02:00
|
|
|
$portal->lmLog( "SAML choice force not tested: $@", 'debug' );
|
2010-09-23 18:41:39 +02:00
|
|
|
}
|
2010-09-10 21:52:44 +02:00
|
|
|
|
|
|
|
# Force SAML choice if needed
|
|
|
|
if ($samlForce) {
|
|
|
|
$portal->lmLog( "SAML is a forced choice", 'debug' );
|
|
|
|
$portal->{_authChoice} = 'forcedSAML';
|
2015-12-12 14:18:48 +01:00
|
|
|
$portal->{authChoiceModules}->{'forcedSAML'} = 'SAML;SAML;Null';
|
2010-09-10 21:52:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return $self unless $portal->{_authChoice};
|
|
|
|
|
|
|
|
# Find modules associated to authChoice
|
|
|
|
my ( $auth, $userDB, $passwordDB ) =
|
2016-01-02 10:35:40 +01:00
|
|
|
split( /[;\|]/,
|
|
|
|
$portal->{authChoiceModules}->{ $portal->{_authChoice} } );
|
2010-09-10 21:52:44 +02:00
|
|
|
|
|
|
|
if ( $auth and $userDB and $passwordDB ) {
|
|
|
|
|
|
|
|
my $modulePrefix = 'Lemonldap::NG::Portal::';
|
|
|
|
my $authModule = $modulePrefix . 'Auth' . $auth;
|
|
|
|
my $userDBModule = $modulePrefix . 'UserDB' . $userDB;
|
|
|
|
my $passwordDBModule = $modulePrefix . 'PasswordDB' . $passwordDB;
|
|
|
|
|
2010-09-13 17:14:19 +02:00
|
|
|
foreach my $module ( $authModule, $userDBModule, $passwordDBModule ) {
|
|
|
|
$portal->abort( 'Bad configuration', "Unable to load $module" )
|
|
|
|
unless $portal->loadModule($module);
|
2010-09-10 21:52:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$self->{modules} = [
|
2010-09-23 18:41:39 +02:00
|
|
|
{ m => $authModule, n => $auth },
|
|
|
|
{ m => $userDBModule, n => $userDB },
|
2010-09-13 17:14:19 +02:00
|
|
|
{ m => $passwordDBModule, n => $passwordDB }
|
2010-09-10 21:52:44 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
$portal->lmLog( "Authentication module $auth selected", 'debug' );
|
|
|
|
$portal->lmLog( "User module $userDB selected", 'debug' );
|
|
|
|
$portal->lmLog( "Password module $passwordDB selected", 'debug' );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
$portal->abort( "Authentication choice "
|
|
|
|
. $self->{_authChoice}
|
|
|
|
. " value is invalid" );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method int try(string sub,int type)
|
|
|
|
# Main method: try to call $sub method in the choosen module.
|
|
|
|
# If no choice, return default behavior
|
|
|
|
# @param sub name of the method to launch
|
|
|
|
# @param type 0 for authentication, 1 for userDB, 2 for passworDB
|
|
|
|
# @return Lemonldap::NG::Portal error code returned by method $sub
|
|
|
|
sub try {
|
2016-01-02 10:29:05 +01:00
|
|
|
my ( $self, $sub, $type ) = @_;
|
2010-09-10 21:52:44 +02:00
|
|
|
|
|
|
|
# Default behavior in no choice
|
|
|
|
unless ( defined $self->{modules} ) {
|
2011-11-15 10:08:16 +01:00
|
|
|
return PE_FIRSTACCESS if ( $sub eq 'extractFormInfo' );
|
2010-09-10 21:52:44 +02:00
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Launch wanted subroutine
|
|
|
|
my $s = $self->{modules}->[$type]->{m} . "::$sub";
|
|
|
|
my $name = $self->{modules}->[$type]->{n};
|
|
|
|
|
|
|
|
$self->{p}
|
|
|
|
->lmLog( "Try to launch $sub on module $name (type $type)", 'debug' );
|
|
|
|
|
|
|
|
return $self->{p}->$s();
|
|
|
|
}
|
|
|
|
|
|
|
|
package Lemonldap::NG::Portal::Simple;
|
|
|
|
|
|
|
|
## @method private Lemonldap::NG::Portal::_Choice _choice()
|
|
|
|
# Return Lemonldap::NG::Portal::_Choice object and builds it if it was not build
|
|
|
|
# before. This method is used if authentication is set to "Choice".
|
|
|
|
# @return Lemonldap::NG::Portal::_Choice object
|
|
|
|
sub _choice {
|
|
|
|
my $self = shift;
|
2011-01-25 11:57:45 +01:00
|
|
|
|
|
|
|
# Check if choice is already built
|
2010-09-10 21:52:44 +02:00
|
|
|
return $self->{_choice} if ( $self->{_choice} );
|
2011-01-25 11:57:45 +01:00
|
|
|
|
|
|
|
# Get authentication choice
|
|
|
|
$self->{_authChoice} = $self->param( $self->{authChoiceParam} );
|
|
|
|
|
|
|
|
# Check XSS Attack
|
|
|
|
$self->{_authChoice} = ""
|
|
|
|
if ( $self->{_authChoice}
|
|
|
|
and
|
|
|
|
$self->checkXSSAttack( $self->{authChoiceParam}, $self->{_authChoice} )
|
|
|
|
);
|
|
|
|
|
|
|
|
$self->lmLog( "Authentication choice found: " . $self->{_authChoice},
|
|
|
|
'debug' )
|
|
|
|
if $self->{_authChoice};
|
|
|
|
|
2010-09-10 21:52:44 +02:00
|
|
|
return $self->{_choice} = Lemonldap::NG::Portal::_Choice->new($self);
|
|
|
|
}
|
|
|
|
|
|
|
|
## @method private Lemonldap::NG::Portal::_Choice _buildAuthLoop()
|
|
|
|
# Build authentication loop displayed in template
|
|
|
|
# @return authLoop rarray reference
|
|
|
|
sub _buildAuthLoop {
|
|
|
|
my $self = shift;
|
|
|
|
my @authLoop;
|
|
|
|
|
|
|
|
# Test authentication choices
|
|
|
|
unless ( ref $self->{authChoiceModules} eq 'HASH' ) {
|
|
|
|
$self->lmLog( "No authentication choices defined", 'warn' );
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ( sort keys %{ $self->{authChoiceModules} } ) {
|
|
|
|
|
|
|
|
my $name = $_;
|
|
|
|
|
2010-09-27 10:53:16 +02:00
|
|
|
# Ignore 'forcedSAML'
|
|
|
|
next if $name eq 'forcedSAML';
|
|
|
|
|
2010-09-10 21:52:44 +02:00
|
|
|
# Name can have a digit as first character
|
|
|
|
# for sorting purpose
|
|
|
|
# Remove it in displayed name
|
|
|
|
$name =~ s/^(\d*)?(\s*)?//;
|
|
|
|
|
2011-06-10 22:22:38 +02:00
|
|
|
# Replace also _ by space for a nice display
|
|
|
|
$name =~ s/\_/ /g;
|
|
|
|
|
2010-09-10 21:52:44 +02:00
|
|
|
# Find modules associated to authChoice
|
2013-10-11 11:01:54 +02:00
|
|
|
my ( $auth, $userDB, $passwordDB, $url ) =
|
2015-12-12 14:18:48 +01:00
|
|
|
split( /[;\|]/, $self->{authChoiceModules}->{$_} );
|
2010-09-10 21:52:44 +02:00
|
|
|
|
|
|
|
if ( $auth and $userDB and $passwordDB ) {
|
|
|
|
|
2013-10-11 11:01:54 +02:00
|
|
|
# Default URL
|
|
|
|
$url ||= "#";
|
|
|
|
|
2010-09-10 21:52:44 +02:00
|
|
|
# Options to store in the loop
|
2013-10-11 11:01:54 +02:00
|
|
|
my $optionsLoop =
|
|
|
|
{ name => $name, key => $_, module => $auth, url => $url };
|
2010-09-10 21:52:44 +02:00
|
|
|
|
|
|
|
# Get displayType for this module
|
2012-03-24 15:47:47 +01:00
|
|
|
my $modulePrefix = 'Lemonldap::NG::Portal::';
|
|
|
|
my $authModule = $modulePrefix . 'Auth' . $auth;
|
|
|
|
$self->loadModule($authModule);
|
|
|
|
my $displayType = &{ $authModule . '::getDisplayType' };
|
2010-09-10 21:52:44 +02:00
|
|
|
|
2012-03-24 15:47:47 +01:00
|
|
|
$self->lmLog( "Display type $displayType for module $auth",
|
|
|
|
'debug' );
|
|
|
|
$optionsLoop->{$displayType} = 1;
|
2010-09-10 21:52:44 +02:00
|
|
|
|
|
|
|
# Register item in loop
|
|
|
|
push @authLoop, $optionsLoop;
|
|
|
|
|
|
|
|
$self->lmLog( "Authentication choice $name will be displayed",
|
|
|
|
'debug' );
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
$self->abort("Authentication choice $_ value is invalid");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return \@authLoop;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
1;
|
|
|
|
|