From a04bbf15b7323919bdc01d2ae90b5d7f431095a9 Mon Sep 17 00:00:00 2001 From: Xavier Date: Mon, 2 Sep 2019 23:00:51 +0200 Subject: [PATCH] Add timeout for configuration load (#1908) --- .../lib/Lemonldap/NG/Common/Conf.pm | 35 ++++++++---- lemonldap-ng-handler/MANIFEST | 4 ++ .../Lemonldap/NG/Handler/ApacheMP2/Fail.pm | 10 ++++ .../lib/Lemonldap/NG/Handler/Lib/Fail.pm | 11 ++++ .../lib/Lemonldap/NG/Handler/Lib/PSGI.pm | 7 +-- .../lib/Lemonldap/NG/Handler/Main/Run.pm | 7 ++- .../lib/Lemonldap/NG/Handler/PSGI/Fail.pm | 8 +++ .../lib/Lemonldap/NG/Handler/Server/Fail.pm | 10 ++++ lemonldap-ng-portal/MANIFEST | 4 ++ lemonldap-ng-portal/t/03-ConfTimeout.t | 45 ++++++++++++++++ .../{03-AuthTimeout.t => 03-SessionTimeout.t} | 0 .../NG/Common/Conf/Backends/Timeout.pm | 17 ++++++ lemonldap-ng-portal/t/test-lib.pm | 54 +++++++++++-------- scripts/parameters-for-wiki.pl | 1 + 14 files changed, 174 insertions(+), 39 deletions(-) create mode 100644 lemonldap-ng-handler/lib/Lemonldap/NG/Handler/ApacheMP2/Fail.pm create mode 100644 lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/Fail.pm create mode 100644 lemonldap-ng-handler/lib/Lemonldap/NG/Handler/PSGI/Fail.pm create mode 100644 lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Server/Fail.pm create mode 100644 lemonldap-ng-portal/t/03-ConfTimeout.t rename lemonldap-ng-portal/t/{03-AuthTimeout.t => 03-SessionTimeout.t} (100%) create mode 100644 lemonldap-ng-portal/t/lib/Lemonldap/NG/Common/Conf/Backends/Timeout.pm diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf.pm index 49ce8c846..4df4941c6 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf.pm @@ -397,47 +397,60 @@ sub getDBConf { return $conf; } +sub _launch { + my $self = shift; + my $sub = shift; + my $res; + eval { + local $SIG{ALRM} = sub { die "TIMEOUT\n" }; + alarm ($self->{confTimeout} || 10); + $res = &{ $self->{type} . "::$sub" }( $self, @_ ); + alarm 0; + }; + $msg .= $@ if $@; + return $res; +} + ## @method boolean prereq() # Call prereq() from the $self->{type} package. # @return True if succeed sub prereq { - return &{ $_[0]->{type} . '::prereq' }(@_); + return shift->_launch( 'prereq', @_ ); } ## @method @ available() # Call available() from the $self->{type} package. # @return list of available configuration numbers sub available { - return &{ $_[0]->{type} . '::available' }(@_); + return shift->_launch( 'available', @_ ); } ## @method int lastCfg() # Call lastCfg() from the $self->{type} package. # @return Number of the last configuration available sub lastCfg { - my $result = &{ $_[0]->{type} . '::lastCfg' }(@_) || "0"; - return $result; + return shift->_launch( 'lastCfg', @_ ) || 0; } ## @method boolean lock() # Call lock() from the $self->{type} package. # @return True if succeed sub lock { - return &{ $_[0]->{type} . '::lock' }(@_); + return shift->_launch( 'lock', @_ ); } ## @method boolean isLocked() # Call isLocked() from the $self->{type} package. # @return True if database is locked sub isLocked { - return &{ $_[0]->{type} . '::isLocked' }(@_); + return shift->_launch( 'isLocked', @_ ); } ## @method boolean unlock() # Call unlock() from the $self->{type} package. # @return True if succeed sub unlock { - return &{ $_[0]->{type} . '::unlock' }(@_); + return shift->_launch( 'unlock', @_ ); } ## @method int store(hashRef conf) @@ -445,14 +458,14 @@ sub unlock { # @param $conf Lemondlap configuration serialized # @return Number of new configuration stored if succeed, 0 else. sub store { - return &{ $_[0]->{type} . '::store' }(@_); + return shift->_launch( 'store', @_ ); } ## @method load(int cfgNum, arrayRef fields) # Call load() from the $self->{type} package. # @return Lemonldap::NG Configuration hashRef if succeed, 0 else. sub load { - return &{ $_[0]->{type} . '::load' }(@_); + return shift->_launch( 'load', @_ ); } ## @method boolean delete(int cfgNum) @@ -463,7 +476,7 @@ sub delete { my ( $self, $c ) = @_; my @a = $self->available(); if ( grep( /^$c$/, @a ) ) { - return &{ $self->{type} . '::delete' }( $self, $c ); + return $self->_launch( 'delete', $self, $c ); } else { return 0; @@ -471,7 +484,7 @@ sub delete { } sub logError { - return &{ $_[0]->{type} . '::logError' }(@_); + return shift->_launch( 'logError', @_ ); } 1; diff --git a/lemonldap-ng-handler/MANIFEST b/lemonldap-ng-handler/MANIFEST index a85872cc5..8b773a084 100644 --- a/lemonldap-ng-handler/MANIFEST +++ b/lemonldap-ng-handler/MANIFEST @@ -9,6 +9,7 @@ lib/Lemonldap/NG/Handler/ApacheMP2/AuthBasic.pm lib/Lemonldap/NG/Handler/ApacheMP2/CDA.pm lib/Lemonldap/NG/Handler/ApacheMP2/DevOps.pm lib/Lemonldap/NG/Handler/ApacheMP2/DevOpsST.pm +lib/Lemonldap/NG/Handler/ApacheMP2/Fail.pm lib/Lemonldap/NG/Handler/ApacheMP2/FCGIClient.pm lib/Lemonldap/NG/Handler/ApacheMP2/Main.pm lib/Lemonldap/NG/Handler/ApacheMP2/Menu.pm @@ -20,6 +21,7 @@ lib/Lemonldap/NG/Handler/ApacheMP2/ZimbraPreAuth.pm lib/Lemonldap/NG/Handler/Lib/AuthBasic.pm lib/Lemonldap/NG/Handler/Lib/CDA.pm lib/Lemonldap/NG/Handler/Lib/DevOps.pm +lib/Lemonldap/NG/Handler/Lib/Fail.pm lib/Lemonldap/NG/Handler/Lib/OAuth2.pm lib/Lemonldap/NG/Handler/Lib/PSGI.pm lib/Lemonldap/NG/Handler/Lib/SecureToken.pm @@ -35,6 +37,7 @@ lib/Lemonldap/NG/Handler/Main/SharedVariables.pm lib/Lemonldap/NG/Handler/PSGI.pm lib/Lemonldap/NG/Handler/PSGI/AuthBasic.pm lib/Lemonldap/NG/Handler/PSGI/CDA.pm +lib/Lemonldap/NG/Handler/PSGI/Fail.pm lib/Lemonldap/NG/Handler/PSGI/Main.pm lib/Lemonldap/NG/Handler/PSGI/OAuth2.pm lib/Lemonldap/NG/Handler/PSGI/Router.pm @@ -45,6 +48,7 @@ lib/Lemonldap/NG/Handler/Server/AuthBasic.pm lib/Lemonldap/NG/Handler/Server/CDA.pm lib/Lemonldap/NG/Handler/Server/DevOps.pm lib/Lemonldap/NG/Handler/Server/DevOpsST.pm +lib/Lemonldap/NG/Handler/Server/Fail.pm lib/Lemonldap/NG/Handler/Server/Main.pm lib/Lemonldap/NG/Handler/Server/Nginx.pm lib/Lemonldap/NG/Handler/Server/OAuth2.pm diff --git a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/ApacheMP2/Fail.pm b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/ApacheMP2/Fail.pm new file mode 100644 index 000000000..e5c965163 --- /dev/null +++ b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/ApacheMP2/Fail.pm @@ -0,0 +1,10 @@ +package Lemonldap::NG::Handler::ApacheMP2::Fail; + +use strict; + +use base 'Lemonldap::NG::Handler::Lib::Fail', + 'Lemonldap::NG::Handler::ApacheMP2::Main'; + +our $VERSION = '2.0.6'; + +1; diff --git a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/Fail.pm b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/Fail.pm new file mode 100644 index 000000000..52f3d1314 --- /dev/null +++ b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/Fail.pm @@ -0,0 +1,11 @@ +package Lemonldap::NG::Handler::Lib::Fail; + +use base Lemonldap::NG::Handler::Main; + +sub run { + return $_[0]->SERVER_ERROR; +} + +our $VERSION = '2.0.6'; + +1; diff --git a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/PSGI.pm b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/PSGI.pm index 0000b0246..1f4742c0b 100644 --- a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/PSGI.pm +++ b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/PSGI.pm @@ -21,7 +21,7 @@ sub init { return 0; } unless ( $self->api->checkConf($self) - or $self->{protection} eq 'none' ) + or ( $self->{protection} and $self->{protection} eq 'none' ) ) { $self->error( "Unable to protect this server ($Lemonldap::NG::Common::Conf::msg)" @@ -128,7 +128,8 @@ sub _authAndTrace { eval "require $type"; die $@ if ($@); my ( $res, $session ) = $type->run( $req, $self->{rule} ); - $self->portal( $type->tsv->{portal}->() ); + eval { $self->portal( $type->tsv->{portal}->() ) }; + $self->logger->warn($@) if $@; $req->userData($session) if ($session); if ( $res < 300 ) { @@ -146,7 +147,7 @@ sub _authAndTrace { return [ $res, [ $req->spliceHdrs ], [] ]; } else { - my $s = $type->tsv->{portal}->() . "/lmerror/$res"; + my $s = ( $self->portal ? $self->portal . "/lmerror/$res" : '' ); $s = 'Redirection' . qq{} diff --git a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Main/Run.pm b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Main/Run.pm index 4239fe1a4..764279cda 100644 --- a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Main/Run.pm +++ b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Main/Run.pm @@ -83,8 +83,11 @@ sub checkType { my ( $class, $req ) = @_; if ( time() - $class->lastCheck > $class->checkTime ) { - die("$class: No configuration found") - unless ( $class->checkConf ); + unless ( $class->checkConf ) { + $class->logger->error("$class: No configuration found"); + $req->data->{noTry} = 1; + return 'Fail'; + } } my $vhost = $class->resolveAlias($req); return ( defined $class->tsv->{type}->{$vhost} ) diff --git a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/PSGI/Fail.pm b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/PSGI/Fail.pm new file mode 100644 index 000000000..7adc0b0a9 --- /dev/null +++ b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/PSGI/Fail.pm @@ -0,0 +1,8 @@ +package Lemonldap::NG::Handler::PSGI::Fail; + +use base 'Lemonldap::NG::Handler::Lib::Fail', + 'Lemonldap::NG::Handler::PSGI::Main'; + +our $VERSION = '2.0.6'; + +1; diff --git a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Server/Fail.pm b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Server/Fail.pm new file mode 100644 index 000000000..3bb3df97c --- /dev/null +++ b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Server/Fail.pm @@ -0,0 +1,10 @@ +package Lemonldap::NG::Handler::Server::Fail; + +use strict; + +use base 'Lemonldap::NG::Handler::Lib::Fail', + 'Lemonldap::NG::Handler::Server::Main'; + +our $VERSION = '2.0.0'; + +1; diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index 098563047..f57b9129d 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -435,6 +435,8 @@ t/01-AuthDemo.t t/01-CSP-and-CORS-headers.t t/01-pdata.t t/02-Password-Demo.t +t/03-ConfTimeout.t +t/03-SessionTimeout.t t/03-XSS-protection.t t/04-language-selection.t t/19-Auth-Null.t @@ -615,6 +617,8 @@ t/gpghome/private-keys-v1.d/A076B0E7DB141A919271EE8B581CDFA8DA42F333.key t/gpghome/private-keys-v1.d/B7219440BCCD85200121CFB89F94C8D98C0397B3.key t/gpghome/pubring.kbx t/gpghome/trustdb.gpg +t/lib/Apache/Session/Timeout.pm +t/lib/Lemonldap/NG/Common/Conf/Backends/Timeout.pm t/lib/Lemonldap/NG/Handler/Test.pm t/lib/Lemonldap/NG/Portal/Auth/LDAPPolicy.pm t/lmConf-1.json diff --git a/lemonldap-ng-portal/t/03-ConfTimeout.t b/lemonldap-ng-portal/t/03-ConfTimeout.t new file mode 100644 index 000000000..1958e8d7d --- /dev/null +++ b/lemonldap-ng-portal/t/03-ConfTimeout.t @@ -0,0 +1,45 @@ +use Test::More; +use strict; +use IO::String; +use lib 't/lib'; + +require 't/test-lib.pm'; + +my $res; + +my $client = LLNG::Manager::Test->new( { + confFailure => 1, + ini => { + configStorage => { + type => 'Timeout', + dirName => 't', + confTimeout => 1, + }, + logLevel => 'error', + useSafeJail => 1, + globalStorage => 'Apache::Session::Timeout', + globalStorageOptions => { + Directory => 't/sessions', + LockDirectory => 't/sessions/lock', + timeout => 1, + }, + } + } +); + +diag "Waiting"; +ok( !$client->{p}->init( $client->ini ) ); +ok( $client->app( $client->{p}->run ) ); +ok( + $res = $client->_post( + '/', + IO::String->new('user=dwho&password=dwho'), + length => 23, + ), + 'Auth query' +); +ok( $res->[0] == 500 ); +count(4); +clean_sessions(); + +done_testing( count() ); diff --git a/lemonldap-ng-portal/t/03-AuthTimeout.t b/lemonldap-ng-portal/t/03-SessionTimeout.t similarity index 100% rename from lemonldap-ng-portal/t/03-AuthTimeout.t rename to lemonldap-ng-portal/t/03-SessionTimeout.t diff --git a/lemonldap-ng-portal/t/lib/Lemonldap/NG/Common/Conf/Backends/Timeout.pm b/lemonldap-ng-portal/t/lib/Lemonldap/NG/Common/Conf/Backends/Timeout.pm new file mode 100644 index 000000000..516e558ec --- /dev/null +++ b/lemonldap-ng-portal/t/lib/Lemonldap/NG/Common/Conf/Backends/Timeout.pm @@ -0,0 +1,17 @@ +package Lemonldap::NG::Common::Conf::Backends::Timeout; + +use Lemonldap::NG::Common::Conf::Backends::File; +our @ISA = ('Lemonldap::NG::Common::Conf::Backends::File'); + +sub load { + my $self = shift; + sleep 5; + return $self->SUPER::load(@_); +} + +sub AUTOLOAD { + $AUTOLOAD =~ s/Lemonldap::NG::Common::Conf::Backends::Timeout:://; + return &{"Lemonldap::NG::Common::Conf::Backends::File::$AUTOLOAD"}(@_); +} + +1; diff --git a/lemonldap-ng-portal/t/test-lib.pm b/lemonldap-ng-portal/t/test-lib.pm index 77d556113..92b3dddf2 100644 --- a/lemonldap-ng-portal/t/test-lib.pm +++ b/lemonldap-ng-portal/t/test-lib.pm @@ -140,7 +140,8 @@ sub count_sessions { sub getCache { require Cache::FileCache; - return Cache::FileCache->new( { + return Cache::FileCache->new( + { namespace => 'lemonldap-ng-session', cache_root => $tmpDir, cache_depth => 0, @@ -562,6 +563,8 @@ has p => ( is => 'rw' ); =cut +has confFailure => ( is => 'rw' ); + has ini => ( is => 'rw', lazy => 1, @@ -573,27 +576,30 @@ has ini => ( } $self->{ini} = $ini; main::ok( $self->{p} = $self->class->new(), 'Portal object' ); - main::ok( $self->{p}->init($ini), 'Init' ); - main::ok( $self->{app} = $self->{p}->run(), 'Portal app' ); - main::count(3); - no warnings 'redefine'; - eval + main::count(1); + unless ( $self->confFailure ) { + main::ok( $self->{p}->init($ini), 'Init' ); + main::ok( $self->{app} = $self->{p}->run(), 'Portal app' ); + main::count(2); + no warnings 'redefine'; + eval 'sub Lemonldap::NG::Common::Logger::Std::error {return $_[0]->warn($_[1])}'; - $Lemonldap::NG::Portal::UserDB::Demo::demoAccounts{french} = { - uid => 'french', - cn => 'Frédéric Accents', - mail => 'fa@badwolf.org', - }; - $Lemonldap::NG::Portal::UserDB::Demo::demoAccounts{davros} = { - uid => 'davros', - cn => 'Bad Guy', - mail => 'davros@badguy.org', - }; - $Lemonldap::NG::Portal::UserDB::Demo::demoAccounts{russian} = { - uid => 'russian', - cn => 'Русский', - mail => 'ru@badwolf.org', - }; + $Lemonldap::NG::Portal::UserDB::Demo::demoAccounts{french} = { + uid => 'french', + cn => 'Frédéric Accents', + mail => 'fa@badwolf.org', + }; + $Lemonldap::NG::Portal::UserDB::Demo::demoAccounts{davros} = { + uid => 'davros', + cn => 'Bad Guy', + mail => 'davros@badguy.org', + }; + $Lemonldap::NG::Portal::UserDB::Demo::demoAccounts{russian} = { + uid => 'russian', + cn => 'Русский', + mail => 'ru@badwolf.org', + }; + } $self; } ); @@ -677,7 +683,8 @@ to test content I<(to launch a C for example)>. sub _get { my ( $self, $path, %args ) = @_; - my $res = $self->app->( { + my $res = $self->app->( + { 'HTTP_ACCEPT' => $args{accept} || 'application/json, text/plain, */*', 'HTTP_ACCEPT_LANGUAGE' => 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3', @@ -729,7 +736,8 @@ sub _post { my ( $self, $path, $body, %args ) = @_; die "$body must be a IO::Handle" unless ( ref($body) and $body->can('read') ); - my $res = $self->app->( { + my $res = $self->app->( + { 'HTTP_ACCEPT' => $args{accept} || 'application/json, text/plain, */*', 'HTTP_ACCEPT_LANGUAGE' => 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3', diff --git a/scripts/parameters-for-wiki.pl b/scripts/parameters-for-wiki.pl index 905042c8b..5c2bc9df5 100755 --- a/scripts/parameters-for-wiki.pl +++ b/scripts/parameters-for-wiki.pl @@ -64,6 +64,7 @@ print <