lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Ext2F.pm
Maxime Besson 8de0a89029 Give more customization options for 2F prompt messages
new translations labels for mail and rest, and we now pass the 2F prefix
to templates. It's not used in the default skin, but it should help in
cases where extra second factors are used to offer the user a more
helpful prompt message
2019-08-05 20:08:28 +02:00

156 lines
4.4 KiB
Perl

package Lemonldap::NG::Portal::2F::Ext2F;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADCREDENTIALS
PE_ERROR
PE_FORMEMPTY
PE_OK
PE_SENDRESPONSE
);
our $VERSION = '2.0.4';
extends 'Lemonldap::NG::Portal::Main::SecondFactor';
# INITIALIZATION
has prefix => ( is => 'rw', default => 'ext' );
has random => ( is => 'rw' );
sub init {
my ($self) = @_;
unless ( $self->conf->{ext2fCodeActivation} ) {
foreach (qw(ext2FSendCommand ext2FValidateCommand)) {
unless ( $self->conf->{$_} ) {
$self->error("Missing $_ parameter, aborting");
return 0;
}
}
$self->prefix( $self->conf->{sfPrefix} )
if ( $self->conf->{sfPrefix} );
return $self->SUPER::init();
}
if ( $self->conf->{ext2fCodeActivation} ) {
unless ( $self->conf->{ext2FSendCommand} ) {
$self->error("Missing 'ext2FSendCommand' parameter, aborting");
return 0;
}
$self->random( Lemonldap::NG::Common::Crypto::srandom() );
$self->prefix( $self->conf->{sfPrefix} )
if ( $self->conf->{sfPrefix} );
return $self->SUPER::init();
}
return 0;
}
# RUNNING METHODS
sub run {
my ( $self, $req, $token ) = @_;
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("Ext2F checkLogins set") if ($checkLogins);
# Generate Code to send
my $code;
if ( $self->conf->{ext2fCodeActivation} ) {
$code = $self->random->randregex( $self->conf->{ext2fCodeActivation} );
$self->logger->debug("Generated ext2f code : $code");
$self->ott->updateToken( $token, __ext2fcode => $code );
}
# Prepare command and launch it
$self->logger->debug( 'Launching "Send" external 2F command -> '
. $self->conf->{ext2FSendCommand} );
if (
my $c = $self->launch(
$req->sessionInfo, $self->conf->{ext2FSendCommand}, $code
)
)
{
$self->logger->error("External send command failed (code $c)");
return PE_ERROR;
}
# Prepare form
my $tmp = $self->p->sendHtml(
$req,
'ext2fcheck',
params => {
MAIN_LOGO => $self->conf->{portalMainLogo},
SKIN => $self->p->getSkin($req),
TOKEN => $token,
PREFIX => $self->prefix,
TARGET => '/' . $self->prefix . '2fcheck',
CHECKLOGINS => $checkLogins
}
);
$self->logger->debug("Prepare external 2F verification");
$req->response($tmp);
return PE_SENDRESPONSE;
}
sub verify {
my ( $self, $req, $session ) = @_;
my $usercode;
unless ( $usercode = $req->param('code') ) {
$self->userLogger->error('External 2F: no code found');
return PE_FORMEMPTY;
}
unless ( $self->conf->{ext2fCodeActivation} ) {
# Prepare command and launch it
$self->logger->debug( 'Launching "Validate" external 2F command -> '
. $self->conf->{ext2FValidateCommand} );
$self->logger->debug(" code -> $usercode");
if (
my $c = $self->launch(
$session, $self->conf->{ext2FValidateCommand}, $usercode
)
)
{
$self->userLogger->warn( 'Second factor failed for '
. $session->{ $self->conf->{whatToTrace} } );
$self->logger->error("External verify command failed (code $c)");
return PE_BADCREDENTIALS;
}
return PE_OK;
}
my $savedcode = $session->{__ext2fcode};
unless ($savedcode) {
$self->logger->error(
'Unable to find generated 2F code in token session');
return PE_ERROR;
}
$self->logger->debug("Verifying Ext 2F code: $usercode VS $savedcode");
return PE_OK if ( $usercode eq $savedcode );
$self->userLogger->warn( 'Second factor failed for '
. $session->{ $self->conf->{whatToTrace} } );
return PE_BADCREDENTIALS;
}
# system() is used with an array to avoid shell injection
sub launch {
my ( $self, $session, $command, $code ) = @_;
my @args;
foreach ( split( /\s+/, $command ) ) {
if ( defined $code ) {
s#\$code\b#$code#g;
}
s#\$(\w+)#$session->{$1} // ''#ge;
push @args, $_;
}
$self->logger->debug( "Executing command: " . join( " ", @args ) );
return system @args;
}
1;