Merge branch 'v2.0' into 1783

This commit is contained in:
Christophe Maudoux 2019-06-27 21:11:56 +02:00
commit 8ad895c3b8
51 changed files with 415 additions and 98 deletions

View File

@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "llng-fastcgi-server 1"
.TH llng-fastcgi-server 1 "2019-06-13" "perl v5.28.1" "User Contributed Perl Documentation"
.TH llng-fastcgi-server 1 "2019-06-27" "perl v5.28.1" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l

View File

@ -4,7 +4,7 @@ use strict;
use Mouse;
use Lemonldap::NG::Common::Conf;
our $VERSION = '2.0.0';
our $VERSION = '2.0.5';
has confAccess => (
is => 'rw',
@ -31,6 +31,9 @@ sub info {
my $conf =
$self->confAccess->getConf( { cfgNum => $self->cfgNum, raw => 1 } )
or die $Lemonldap::NG::Common::Conf::msg;
$conf->{cfgAuthorIP} ||= "No IP provided";
$conf->{cfgDate} ||= 0;
$conf->{cfgLog} ||= "No log provided";
print qq{
Num : $conf->{cfgNum}
Author : $conf->{cfgAuthor}

View File

@ -10,7 +10,7 @@ our $VERSION = '2.0.0';
has parser => (
is => 'rw',
builder => sub {
return XML::LibXML->new();
return XML::LibXML->new( load_ext_dtd => 0, expand_entities => 0 );
}
);

View File

@ -11,7 +11,7 @@ sub perlExpr {
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $val");
$cpt->reval("BEGIN { 'warnings'->unimport; } $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; } split( /\n/, $@, 0 ) )

View File

@ -18,7 +18,7 @@ sub perlExpr {
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $val");
$cpt->reval("BEGIN { 'warnings'->unimport; } $val");
my $err = join( '',
grep { $_ =~ /Undefined subroutine/ ? () : $_ } split( /\n/, $@ ) );
return $err ? ( 1, "__badExpression__: $err" ) : (1);

View File

@ -3,6 +3,7 @@
use Lemonldap::NG::Common::Conf;
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Manager::Conf::Parser;
use Lemonldap::NG::Handler::Main::Jail;
use Data::Dumper;
use English qw(-no_match_vars);
use File::Temp;

View File

@ -303,7 +303,7 @@
"hideTree":"Masquer l'arbre",
"httpOnly":"Protection contre javascript",
"https":"HTTPS",
"impersonation":"Usurpation d'identité",
"impersonation":"Simulation d'identité",
"impersonationRule":"Règle d'utilisation",
"impersonationIdRule":"Règle d'utilisation des identités",
"impersonationHiddenAttributes":"Attributs masqués",

View File

@ -734,7 +734,7 @@
"sfaTitle":"Second Factors Authentication",
"sfRequired":"Require 2FA",
"sfRemovedNotification":"Display a message if an expired SF is removed",
"sfRemovedMsgRule":"Activation",
"sfRemovedMsgRule":"激活",
"sfRemovedUseNotif":"Use Notifications plugin",
"sfRemovedNotifMsg":"Notification message",
"sfRemovedNotifRef":"Notification reference",

View File

@ -10,6 +10,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
PE_ERROR
PE_LOGOUT_OK
PE_OK
PE_BADURL
PE_SENDRESPONSE
);
@ -55,6 +56,18 @@ sub init {
},
['GET']
);
# Add CAS Services, so we can check service= parameter on logout
foreach my $casSrv ( keys %{ $self->conf->{casAppMetaDataOptions} } ) {
if ( my $serviceUrl =
$self->conf->{casAppMetaDataOptions}->{$casSrv}
->{casAppMetaDataOptionsService} )
{
push @{ $self->p->{additionalTrustedDomains} }, $serviceUrl;
$self->logger->debug(
"CAS Service $serviceUrl added in trusted domains");
}
}
return $res;
}
@ -265,6 +278,19 @@ sub run {
$logout_service = ''
if ( $self->p->checkXSSAttack( 'service', $logout_service ) );
# If we use access control, check that the service URL is trusted
if ( $self->conf->{casAccessControlPolicy} =~ /^(error|faketicket)$/i )
{
if ( $logout_service
and not $self->p->isTrustedUrl($logout_service) )
{
$self->userLogger->error(
"Untrusted service URL $logout_service"
. "specified for CAS Logout" );
return PE_BADURL;
}
}
# Delete linked CAS sessions
$self->deleteCasSecondarySessions($session_id);

View File

@ -17,7 +17,7 @@ extends 'Lemonldap::NG::Portal::Main::Plugin';
has parser => (
is => 'rw',
builder => sub {
return XML::LibXML->new();
return XML::LibXML->new( load_ext_dtd => 0, expand_entities => 0 );
}
);
@ -32,7 +32,7 @@ has stylesheet => (
( $self->conf->{notificationXSLTfile}
and -e $self->conf->{notificationXSLTfile} )
? $self->conf->{notificationXSLTfile}
: $self->conf->{templatesDir} . '/common/notification.xsl';
: $self->conf->{templateDir} . '/common/notification.xsl';
unless ( -e $styleFile ) {
$self->{logger}->error("$styleFile not found, aborting");
die "$styleFile not found";

View File

@ -36,7 +36,7 @@ sub displayInit {
sub display {
my ( $self, $req ) = @_;
my $skin_dir = $self->conf->{templatesDir};
my $skin_dir = $self->conf->{templateDir};
my ( $skinfile, %templateParams );
# 1. Authentication not complete
@ -438,9 +438,9 @@ sub staticFile {
require Plack::Util;
require Cwd;
require HTTP::Date;
open my $fh, '<:raw', $self->conf->{templatesDir} . "/$file"
open my $fh, '<:raw', $self->conf->{templateDir} . "/$file"
or return $self->sendError( $req,
$self->conf->{templatesDir} . "/$file: $!", 403 );
$self->conf->{templateDir} . "/$file: $!", 403 );
my @stat = stat $file;
Plack::Util::set_io_path( $fh, Cwd::realpath($file) );
return [

View File

@ -39,6 +39,7 @@ has _jsRedirect => ( is => 'rw' );
# TrustedDomain regexp
has trustedDomainsRe => ( is => 'rw' );
has additionalTrustedDomains => ( is => 'rw', default => sub { [] } );
# Lists to store plugins entry-points
my @entryPoints;
@ -269,53 +270,6 @@ sub reloadConf {
unless $self->{_sfEngine} =
$self->loadPlugin( $self->conf->{'sfEngine'} );
# Initialize trusted domain regexp
if ( $self->conf->{trustedDomains}
and $self->conf->{trustedDomains} =~ /^\s*\*\s*$/ )
{
$self->trustedDomainsRe(qr#^https?://#);
}
else {
my $re = Regexp::Assemble->new();
if ( my $td = $self->conf->{trustedDomains} ) {
$td =~ s/^\s*(.*?)\s*/$1/;
foreach ( split( /\s+/, $td ) ) {
next unless ($td);
s#^\.#([^/]+\.)?#;
$self->logger->debug("Domain $_ added in trusted domains");
s/\./\\./g;
# This regexp is valid for the followings hosts:
# - $td
# - $domainlabel.$td
# $domainlabel is build looking RFC2396
# (see Regexp::Common::URI::RFC2396)
$_ =~
s/\*\\\./(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9]\\.)*/g;
$re->add("$_");
}
}
my $p = $self->conf->{portal};
$p =~ s#https?://([^/]*).*$#$1#;
$re->add( quotemeta($p) );
foreach my $vhost ( keys %{ $self->conf->{locationRules} } ) {
$self->logger->debug("Vhost $vhost added in trusted domains");
$re->add( quotemeta($vhost) );
$self->conf->{vhostOptions} ||= {};
if ( my $tmp =
$self->conf->{vhostOptions}->{$vhost}->{vhostAliases} )
{
foreach my $alias ( split /\s+/, $tmp ) {
$self->logger->debug(
"Alias $alias added in trusted domains");
$re->add( quotemeta($alias) );
}
}
}
my $tmp = 'https?://' . $re->as_string . '(?::\d+)?(?:/|$)';
$self->trustedDomainsRe(qr/$tmp/);
}
# Compile macros in _macros, groups in _groups
foreach my $type (qw(macros groups)) {
$self->{"_$type"} = {};
@ -344,6 +298,59 @@ sub reloadConf {
$self->loadPlugin($plugin) or return $self->fail;
}
# Initialize trusted domain regexp
if ( $self->conf->{trustedDomains}
and $self->conf->{trustedDomains} =~ /^\s*\*\s*$/ )
{
$self->trustedDomainsRe(qr#^https?://#);
}
else {
my $re = Regexp::Assemble->new();
if ( my $td = $self->conf->{trustedDomains} ) {
$td =~ s/^\s*(.*?)\s*/$1/;
foreach ( split( /\s+/, $td ) ) {
next unless ($td);
s#^\.#([^/]+\.)?#;
$self->logger->debug("Domain $_ added in trusted domains");
s/\./\\./g;
# This regexp is valid for the followings hosts:
# - $td
# - $domainlabel.$td
# $domainlabel is build looking RFC2396
# (see Regexp::Common::URI::RFC2396)
$_ =~
s/\*\\\./(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9]\\.)*/g;
$re->add("$_");
}
}
foreach ( @{ $self->{additionalTrustedDomains} },
$self->conf->{portal} )
{
my $p = $_;
$p =~ s#https?://([^/]*).*$#$1#;
$re->add( quotemeta($p) );
}
foreach my $vhost ( keys %{ $self->conf->{locationRules} } ) {
$self->logger->debug("Vhost $vhost added in trusted domains");
$re->add( quotemeta($vhost) );
$self->conf->{vhostOptions} ||= {};
if ( my $tmp =
$self->conf->{vhostOptions}->{$vhost}->{vhostAliases} )
{
foreach my $alias ( split /\s+/, $tmp ) {
$self->logger->debug(
"Alias $alias added in trusted domains");
$re->add( quotemeta($alias) );
}
}
}
my $tmp = 'https?://' . $re->as_string . '(?::\d+)?(?:/|$)';
$self->trustedDomainsRe(qr/$tmp/);
}
# Clean $req->pdata after authentication
push @{ $self->endAuth }, sub {
unless ( $_[0]->pdata->{keepPdata} ) {

View File

@ -37,6 +37,14 @@ sub init {
my ($self) = @_;
unless ( $self->noRoute ) {
$self->logger->debug( 'Adding ' . $self->prefix . '2fcheck routes' );
$self->addAuthRoute(
$self->prefix . '2fcheck' => '_verify',
['POST']
);
$self->addAuthRoute(
$self->prefix . '2fcheck' => '_redirect',
['GET']
);
$self->addUnauthRoute(
$self->prefix . '2fcheck' => '_verify',
['POST']

View File

@ -58,7 +58,9 @@ sub ask {
sub confirm {
my ( $self, $req ) = @_;
$req->pdata->{keepPdata} = 1;
# Disabled due to #1821
#$req->pdata->{keepPdata} = 1;
my $upg;
if ( my $t = $req->param('upgrading') ) {
if ( $self->ott->getToken($t) ) {

View File

@ -173,7 +173,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -204,7 +204,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -186,7 +186,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -190,7 +190,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -152,7 +152,7 @@ ok( $res->{cn} eq 'Frédéric Accents', 'UTF-8 values' )
or explain( $res, 'cn => Frédéric Accents' );
count(3);
# Logout initiated by CAS
# Logout initiated by CAS, try with invalid service URL first
switch ('issuer');
ok(
$res = $issuer->_get(
@ -164,7 +164,22 @@ ok(
'Query SP for logout'
);
count(1);
expectRedirection( $res, 'http://url.test/' );
ok( $res->[2]->[0] =~ m%<span trmsg="37"></span>%, ' PE37 found' );
count(1);
# Logout initiated by CAS, try with valid service URL
ok(
$res = $issuer->_get(
'/cas/logout',
query => 'service=http://auth.sp.com/',
cookie => "lemonldap=$idpId,llngcasserver=idp",
accept => 'text/html'
),
'Query SP for logout'
);
count(1);
expectRedirection( $res, 'http://auth.sp.com/' );
# Verify that user has been disconnected
ok( $res = $issuer->_get( '/', cookie => "lemonldap=$idpId" ), 'Query IdP' );
@ -185,7 +200,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',
@ -193,8 +207,13 @@ sub issuer {
issuerDBCASActivation => 1,
casAttr => 'uid',
casAttributes => { cn => 'cn', uid => 'uid', },
casAccessControlPolicy => 'none',
casAccessControlPolicy => 'error',
multiValuesSeparator => ';',
casAppMetaDataOptions => {
sp => {
casAppMetaDataOptionsService => 'http://auth.sp.com',
},
},
}
}
);

View File

@ -204,7 +204,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -258,7 +258,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -258,7 +258,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -110,7 +110,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -229,7 +229,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -118,7 +118,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -221,7 +221,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -159,7 +159,6 @@ sub issuer {
skipRenewConfirmation => 1,
logLevel => $debug,
#templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -313,7 +313,6 @@ sub issuer {
ini => {
skipRenewConfirmation => 1,
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Choice',

View File

@ -93,7 +93,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -193,7 +193,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -308,7 +308,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -145,7 +145,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -168,7 +168,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -127,7 +127,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -97,7 +97,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -163,7 +163,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -137,7 +137,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -128,7 +128,6 @@ sub issuer {
return LLNG::Manager::Test->new( {
ini => {
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -228,7 +228,6 @@ sub issuer {
ini => {
skipRenewConfirmation => 1,
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -213,7 +213,6 @@ sub issuer {
ini => {
skipRenewConfirmation => 1,
logLevel => $debug,
templatesDir => 'site/htdocs/static',
domain => 'idp.com',
portal => 'http://auth.idp.com',
authentication => 'Demo',

View File

@ -39,7 +39,6 @@ q{INSERT INTO notifications VALUES ('dwho','testref','2016-05-30 00:00:00',?,nul
logLevel => 'error',
useSafeJail => 1,
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'DBI',
notificationStorageOptions => {
dbiChain => "dbi:SQLite:dbname=$file",

View File

@ -26,7 +26,6 @@ my $client = LLNG::Manager::Test->new( {
logLevel => 'error',
useSafeJail => 1,
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => {
dirName => 't'

View File

@ -26,7 +26,6 @@ my $client = LLNG::Manager::Test->new( {
logLevel => 'error',
useSafeJail => 1,
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => { dirName => 't' },
oldNotifFormat => 0,

View File

@ -22,7 +22,6 @@ my $client = LLNG::Manager::Test->new( {
useSafeJail => 1,
notification => 1,
notificationServer => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => {
dirName => 't'

View File

@ -38,7 +38,6 @@ qq{INSERT INTO notifications VALUES ('dwho','testref','2016-05-30 00:00:00','<?x
logLevel => 'error',
useSafeJail => 1,
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'DBI',
notificationStorageOptions => {
dbiChain => "dbi:SQLite:dbname=$file",

View File

@ -30,7 +30,6 @@ SKIP: {
logLevel => 'error',
useSafeJail => 1,
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => { dirName => 't' },
oldNotifFormat => 1,

View File

@ -64,7 +64,6 @@ SKIP: {
useSafeJail => 1,
notification => 1,
notificationServer => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => {
dirName => 't'

View File

@ -0,0 +1,126 @@
use Test::More;
use strict;
use IO::String;
use Data::Dumper;
require 't/test-lib.pm';
require 't/smtp.pm';
use_ok('Lemonldap::NG::Common::FormEncode');
count(1);
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
upgradeSession => 1,
authentication => 'Choice',
apacheAuthnLevel => 5,
userDB => 'Same',
'authChoiceModules' => {
'strong' => 'Apache;Demo;Null;;;{}',
'weak' => 'Demo;Demo;Null;;;{}'
},
'vhostOptions' => {
'test1.example.com' => {
'vhostAuthnLevel' => 3
},
},
}
}
);
# Try to authenticate
# -------------------
ok(
my $res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho&lmAuth=weak'),
length => 35,
accept => 'text/html',
),
'Auth query'
);
count(1);
my $id = expectCookie($res);
# After attempting to access test1,
# the handler sends up back to /upgradesession
# --------------------------------------------
ok(
my $res = $client->_get(
'/upgradesession',
query => 'url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29t',
accept => 'text/html',
cookie => "lemonldap=$id",
),
'Upgrade session query'
);
count(1);
my ( $host, $url, $query ) =
expectForm( $res, undef, '/upgradesession', 'confirm', 'url' );
# Accept session upgrade
# ----------------------
ok(
my $res = $client->_post(
'/upgradesession',
IO::String->new($query),
length => length($query),
accept => 'text/html',
cookie => "lemonldap=$id",
),
'Accept session upgrade query'
);
count(1);
my $pdata = expectCookie( $res, 'lemonldappdata' );
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'upgrading', 'url' );
$query = $query . "&lmAuth=strong";
# Attempt login with the "strong" auth choice
# this should trigger 2FA
# -------------------------------------------
ok(
my $res = $client->_post(
'/upgradesession',
IO::String->new($query),
length => length($query),
accept => 'text/html',
cookie => "lemonldap=$id;lemonldappdata=$pdata",
custom => {
REMOTE_USER => 'dwho',
},
),
'Post login'
);
count(1);
$pdata = expectCookie( $res, 'lemonldappdata' );
$id = expectCookie($res);
expectRedirection( $res, 'http://test1.example.com' );
# Make pdata was cleared and we aren't being redirected
ok(
my $res = $client->_get(
'/',
accept => 'text/html',
cookie => "lemonldap=$id;lemonldappdata=$pdata",
),
'Post login'
);
count(1);
expectOK($res);
clean_sessions();
done_testing( count() );

View File

@ -23,7 +23,6 @@ SKIP: {
sfRemovedUseNotif => 1,
portalMainLogo => 'common/logos/logo_llng_old.png',
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => { dirName => 't' },
oldNotifFormat => 0,

View File

@ -23,7 +23,6 @@ SKIP: {
sfRemovedUseNotif => 1,
portalMainLogo => 'common/logos/logo_llng_old.png',
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => { dirName => 't' },
oldNotifFormat => 1,

View File

@ -0,0 +1,159 @@
use Test::More;
use strict;
use IO::String;
use Data::Dumper;
require 't/test-lib.pm';
require 't/smtp.pm';
use_ok('Lemonldap::NG::Common::FormEncode');
count(1);
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
upgradeSession => 1,
mail2fActivation => '$_choice eq "strong"',
mail2fCodeRegex => '\d{4}',
mail2fAuthnLevel => 5,
authentication => 'Choice',
userDB => 'Same',
'authChoiceModules' => {
'strong' => 'Demo;Demo;Null;;;{}',
'weak' => 'Demo;Demo;Null;;;{}'
},
'vhostOptions' => {
'test1.example.com' => {
'vhostAuthnLevel' => 3
},
},
}
}
);
# Try to authenticate
# -------------------
ok(
my $res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho&lmAuth=weak'),
length => 35,
accept => 'text/html',
),
'Auth query'
);
count(1);
my $id = expectCookie($res);
# After attempting to access test1,
# the handler sends up back to /upgradesession
# --------------------------------------------
ok(
my $res = $client->_get(
'/upgradesession',
query => 'url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29t',
accept => 'text/html',
cookie => "lemonldap=$id",
),
'Upgrade session query'
);
count(1);
my ( $host, $url, $query ) =
expectForm( $res, undef, '/upgradesession', 'confirm', 'url' );
# Accept session upgrade
# ----------------------
ok(
my $res = $client->_post(
'/upgradesession',
IO::String->new($query),
length => length($query),
accept => 'text/html',
cookie => "lemonldap=$id",
),
'Accept session upgrade query'
);
count(1);
my $pdata = expectCookie( $res, 'lemonldappdata' );
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'upgrading', 'url' );
$query = $query . "&user=dwho&password=dwho&lmAuth=strong";
# Attempt login with the "strong" auth choice
# this should trigger 2FA
# -------------------------------------------
ok(
my $res = $client->_post(
'/upgradesession',
IO::String->new($query),
length => length($query),
accept => 'text/html',
cookie => "lemonldap=$id;lemonldappdata=$pdata",
),
'Post login'
);
count(1);
my $pdata = expectCookie( $res, 'lemonldappdata' );
( $host, $url, $query ) =
expectForm( $res, undef, '/mail2fcheck', 'token', 'code' );
ok(
$res->[2]->[0] =~
qr%<input name="code" value="" class="form-control" id="extcode" trplaceholder="code" autocomplete="off" />%,
'Found EXTCODE input'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
ok( mail() =~ m%<b>(\d{4})</b>%, 'Found 2F code in mail' )
or print STDERR Dumper( mail() );
count(1);
my $code = $1;
# Post 2F code
# ------------
$query =~ s/code=/code=${code}/;
ok(
$res = $client->_post(
'/mail2fcheck',
IO::String->new($query),
length => length($query),
accept => 'text/html',
cookie => "lemonldap=$id;lemonldappdata=$pdata",
),
'Post code'
);
count(1);
$pdata = expectCookie( $res, 'lemonldappdata' );
$id = expectCookie($res);
expectRedirection( $res, 'http://test1.example.com' );
# Make pdata was cleared and we aren't being redirected
ok(
my $res = $client->_get(
'/',
accept => 'text/html',
cookie => "lemonldap=$id;lemonldappdata=$pdata",
),
'Post login'
);
count(1);
expectOK($res);
clean_sessions();
done_testing( count() );