From 09d929b1fff5335436833fa80bcfad9ff453de72 Mon Sep 17 00:00:00 2001 From: Xavier Guimard Date: Mon, 27 Jan 2020 18:32:59 +0100 Subject: [PATCH 01/94] Change Manager framework to plugins --- .../lib/Lemonldap/NG/Manager.pm | 99 ++++++++++++++----- .../lib/Lemonldap/NG/Manager/2ndFA.pm | 6 +- .../lib/Lemonldap/NG/Manager/Api.pm | 6 +- .../lib/Lemonldap/NG/Manager/Cli.pm | 12 +-- .../lib/Lemonldap/NG/Manager/Conf.pm | 45 +++------ .../lib/Lemonldap/NG/Manager/Conf/Parser.pm | 2 - .../lib/Lemonldap/NG/Manager/Notifications.pm | 6 +- .../lib/Lemonldap/NG/Manager/Plugin.pm | 51 ++++++++++ .../lib/Lemonldap/NG/Manager/Sessions.pm | 8 +- .../lib/Lemonldap/NG/Manager/Viewer.pm | 33 ++++++- lemonldap-ng-manager/t/12-save-changed-conf.t | 4 +- lemonldap-ng-manager/t/70-viewer.t | 13 +-- 12 files changed, 199 insertions(+), 86 deletions(-) create mode 100644 lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Plugin.pm diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm index 99d99ee31..18dc91289 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm @@ -24,6 +24,9 @@ extends 'Lemonldap::NG::Common::Conf::AccessLib', has csp => ( is => 'rw' ); +has loadedPlugins => ( is => 'rw', default => sub { [] } ); +has hLoadedPlugins => ( is => 'rw', default => sub { {} } ); + ## @method boolean init($args) # Launch initialization method # @@ -52,32 +55,50 @@ sub init { return 0; } + my $conf = $self->confAcc->getConf; + $conf->{$_} = $args->{$_} foreach(keys %$args); + $self->{enabledModules} ||= "conf, sessions, notifications, 2ndFA, api"; my @links; my @enabledModules = - map { push @links, $_; "Lemonldap::NG::Manager::" . ucfirst($_) } + map { + my @res = ( "Lemonldap::NG::Manager::" . ucfirst($_) ); + if ( my $tmp = $self->loadPlugin( @res, $conf ) ) { + $self->logger->debug("Plugin $_ loaded"); + push @links, $_; + push @{ $self->loadedPlugins }, $tmp; + $self->hLoadedPlugins->{$_} = $tmp; + } + else { + $self->logger->error("Unable to load $_, skipping"); + @res = (); + } + (@res); + } split( /[,\s]+/, $self->{enabledModules} ); - extends 'Lemonldap::NG::Handler::PSGI::Router', @enabledModules; - my @working; - my $conf = $self->confAcc->getConf; + unless (@enabledModules) { + $self->logger->error('No plugins loaded, aborting'); + return 0; + } unless ($conf) { require Lemonldap::NG::Manager::Conf::Zero; $conf = Lemonldap::NG::Manager::Conf::Zero::zeroConf(); } - for ( my $i = 0 ; $i < @enabledModules ; $i++ ) { - my $mod = $enabledModules[$i]; - no strict 'refs'; - if ( &{"${mod}::addRoutes"}( $self, $conf ) ) { - $self->logger->debug("Module $mod enabled"); - push @working, $mod; - } - else { - $links[$i] = undef; - $self->logger->error( - "Module $mod can not be enabled: " . $self->error ); - } - } - return 0 unless (@working); + + # TODO: -> loadPlugin + #for ( my $i = 0 ; $i < @enabledModules ; $i++ ) { + # my $mod = $enabledModules[$i]; + # no strict 'refs'; + # if ( &{"${mod}::addRoutes"}( $self, $conf ) ) { + # $self->logger->debug("Module $mod enabled"); + # push @working, $mod; + # } + # else { + # $links[$i] = undef; + # $self->logger->error( + # "Module $mod can not be enabled: " . $self->error ); + # } + #} $self->addRoute( links => 'links', ['GET'] ); $self->addRoute( 'psgi.js' => 'sendJs', ['GET'] ); @@ -88,13 +109,14 @@ sub init { ); # Avoid restricted users to access configuration by default route - my $defaultMod = $self->{defaultModule} || 'conf'; + my $defaultMod = $self->{defaultModule} = + $self->{defaultModule} || $enabledModules[0]; $self->logger->debug("Default module -> $defaultMod"); my ($index) = - grep { $working[$_] =~ /::$defaultMod$/i } ( 0 .. $#working ); - $index //= $#working; + grep { $enabledModules[$_] eq $defaultMod } ( 0 .. $#enabledModules ); + $index //= 0; $self->logger->debug("Default index -> $index"); - $self->defaultRoute( $working[$index]->defaultRoute ); + $self->defaultRoute( $self->loadedPlugins->[$index]->defaultRoute ); # Find out more glyphicones at https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp my $linksIcons = { @@ -110,7 +132,7 @@ sub init { next unless ( defined $links[$i] ); push @{ $self->links }, { - target => $enabledModules[$i]->defaultRoute, + target => $self->loadedPlugins->[$i]->defaultRoute, title => $links[$i], icon => $linksIcons->{ $links[$i] } }; @@ -141,13 +163,14 @@ sub init { sub tplParams { my ( $self, $req ) = @_; - my $res = $self->brwRule->( $req, $req->{userData} ) || 0; + my $res = eval { $self->hLoadedPlugins->{viewer}->brwRule->( $req, $req->{userData} ) } || 0; return ( VERSION => $VERSION, ALLOWBROWSER => $res ); } sub javascript { my ( $self, $req ) = @_; - my $res = $self->diffRule->( $req, $req->{userData} ) || 0; + my $res = eval { $self->hLoadedPlugins->{viewer}->diffRule->( $req, $req->{userData} )} || 0; + print STDERR $@ if $@; my $impPrefix = $self->{impersonationPrefix}; my $ttl = $self->{timeout} || 72000; @@ -176,6 +199,32 @@ sub sendHtml { return $res; } +sub loadPlugin { + my ( $self, $plugin, $conf ) = @_; + unless ($plugin) { + require Carp; + Carp::confess('Calling loadPugin without arg !'); + } + my $obj; + $plugin = "Lemonldap::NG::Manager$plugin" if ( $plugin =~ /^::/ ); + + eval "require $plugin"; + if ($@) { + $self->logger->error("$plugin load error: $@"); + return 0; + } + eval { + $obj = $plugin->new( { p => $self, conf => $conf } ); + $self->logger->debug("Module $plugin loaded"); + }; + if ($@) { + $self->error("Unable to build $plugin object: $@"); + return 0; + } + ( $obj and $obj->init($conf) ) or return 0; + return $obj; +} + 1; __END__ diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm index 3f8ea9164..2602ab5c5 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm @@ -13,7 +13,8 @@ use Lemonldap::NG::Common::Conf::ReConstants; use feature 'state'; -extends 'Lemonldap::NG::Common::Conf::AccessLib', +extends 'Lemonldap::NG::Manager::Plugin', + 'Lemonldap::NG::Common::Conf::AccessLib', 'Lemonldap::NG::Common::Session::REST'; our $VERSION = '2.0.2'; @@ -24,7 +25,7 @@ our $VERSION = '2.0.2'; use constant defaultRoute => '2ndfa.html'; -sub addRoutes { +sub init { my ( $self, $conf ) = @_; # Remote Procedure are defined in Lemonldap::NG::Common::Session::REST @@ -46,6 +47,7 @@ sub addRoutes { $self->{multiValuesSeparator} ||= '; '; $self->{hiddenAttributes} //= "_password"; $self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = '1'; + return 1; } ################### diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api.pm index 7f8dd4312..77cecb880 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api.pm @@ -5,7 +5,8 @@ use 5.10.0; use utf8; use Mouse; -extends 'Lemonldap::NG::Common::Conf::RESTServer', +extends 'Lemonldap::NG::Manager::Plugin', + 'Lemonldap::NG::Common::Conf::RESTServer', 'Lemonldap::NG::Common::Session::REST'; use Lemonldap::NG::Manager::Api::2F; @@ -20,7 +21,7 @@ our $VERSION = '2.0.7'; use constant defaultRoute => 'api.html'; -sub addRoutes { +sub init { my ( $self, $conf ) = @_; # HTML template @@ -148,6 +149,7 @@ sub addRoutes { $self->{multiValuesSeparator} ||= '; '; $self->{hiddenAttributes} //= "_password"; $self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = '1'; + return 1; } 1; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm index be6662bd9..3af7641cc 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm @@ -75,7 +75,7 @@ sub set { } } require Clone; - my $new = Clone::clone( $self->mgr->currentConf ); + my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf ); foreach my $key ( keys %pairs ) { $self->_setKey( $new, $key, $pairs{$key} ); } @@ -100,7 +100,7 @@ sub addKey { push @list, [ $root, $newKey, $value ]; } require Clone; - my $new = Clone::clone( $self->mgr->currentConf ); + my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf ); foreach my $el (@list) { my @path = split $sep, $el->[0]; if ( $#path == 0 ) { @@ -141,7 +141,7 @@ sub delKey { push @list, [ $root, $key ]; } require Clone; - my $new = Clone::clone( $self->mgr->currentConf ); + my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf ); foreach my $el (@list) { my @path = split $sep, $el->[0]; if ( $#path == 0 ) { @@ -236,7 +236,7 @@ sub _getKey { warn "Malformed key $base"; return (); } - my $value = $self->mgr->getConfKey( $self->req, $base, noCache => 1 ); + my $value = $self->mgr->hLoadedPlugins->{conf}->getConfKey( $self->req, $base, noCache => 1 ); if ( $self->req->error ) { die $self->req->error; } @@ -272,7 +272,7 @@ sub _save { require Lemonldap::NG::Manager::Conf::Parser; my $parser = Lemonldap::NG::Manager::Conf::Parser->new( { newConf => $new, - refConf => $self->mgr->currentConf, + refConf => $self->mgr->hLoadedPlugins->{conf}->currentConf, req => $self->req } ); @@ -304,7 +304,7 @@ sub _save { "CLI: Configuration $s has been saved by $new->{cfgAuthor}"); $self->logger->info("CLI: Configuration $s saved"); print STDERR "Saved under number $s\n"; - $parser->{status} = [ $self->mgr->applyConf($new) ]; + $parser->{status} = [ $self->mgr->hLoadedPlugins->{conf}->applyConf($new) ]; } else { $self->logger->error("CLI: Configuration not saved!"); diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf.pm index 173345ef9..72bef4df6 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf.pm @@ -17,7 +17,8 @@ use URI::URL; use feature 'state'; -extends 'Lemonldap::NG::Common::Conf::RESTServer'; +extends 'Lemonldap::NG::Manager::Plugin', + 'Lemonldap::NG::Common::Conf::RESTServer'; our $VERSION = '2.0.7'; @@ -28,35 +29,10 @@ our $VERSION = '2.0.7'; use constant defaultRoute => 'manager.html'; has ua => ( is => 'rw' ); -has diffRule => ( is => 'rw', default => sub { 0 } ); -has brwRule => ( is => 'rw', default => sub { 0 } ); -sub addRoutes { +sub init { my ( $self, $conf ) = @_; $self->ua( Lemonldap::NG::Common::UserAgent->new($conf) ); - my $hd = "Lemonldap::NG::Handler::PSGI::Main"; - - # Parse Diff activation rule - $self->logger->debug( - "Diff activation rule -> " . ( $self->{viewerAllowDiff} // 0 ) ); - my $rule = $hd->buildSub( $hd->substitute( $self->{viewerAllowDiff} ) ); - unless ($rule) { - $self->error( - "Bad Diff activation rule -> " . $hd->tsv->{jail}->error ); - return 0; - } - $self->diffRule($rule); - - # Parse Browser activation rule - $self->logger->debug( - "Browser activation rule -> " . ( $self->{viewerAllowBrowser} // 0 ) ); - $rule = $hd->buildSub( $hd->substitute( $self->{viewerAllowBrowser} ) ); - unless ($rule) { - $self->error( - "Bad Browser activation rule -> " . $hd->tsv->{jail}->error ); - return 0; - } - $self->brwRule($rule); # HTML template $self->addRoute( 'manager.html', undef, ['GET'] ) @@ -95,6 +71,7 @@ sub addRoutes { # Url loader ->addRoute( 'prx', undef, ['POST'] ); + return 1; } # 35 - New RSA key pair on demand @@ -268,7 +245,7 @@ sub newConf { } } if ( $res->{result} ) { - if ( $self->{demoMode} ) { + if ( $self->p->{demoMode} ) { $res->{message} = '__demoModeOn__'; } else { @@ -279,7 +256,7 @@ sub newConf { unless ( @{ $parser->{needConfirmation} } && !$args{force} ); if ( $s > 0 ) { $self->userLogger->notice( - 'User ' . $self->userId($req) . " has stored conf $s" ); + 'User ' . $self->p->userId($req) . " has stored conf $s" ); $res->{result} = 1; $res->{cfgNum} = $s; if ( my $status = $self->applyConf( $parser->newConf ) ) { @@ -291,7 +268,7 @@ sub newConf { else { $self->userLogger->notice( 'Saving attempt rejected, asking for confirmation to ' - . $self->userId($req) ); + . $self->p->userId($req) ); $res->{result} = 0; if ( $s == CONFIG_WAS_CHANGED ) { $res->{needConfirm} = 1; @@ -324,7 +301,7 @@ sub newRawConf { } my $res = {}; - if ( $self->{demoMode} ) { + if ( $self->p->{demoMode} ) { $res->{message} = '__demoModeOn__'; } else { @@ -333,14 +310,14 @@ sub newRawConf { my $s = $self->confAcc->saveConf( $new, force => 1 ); if ( $s > 0 ) { $self->userLogger->notice( - 'User ' . $self->userId($req) . " has stored (raw) conf $s" ); + 'User ' . $self->p->userId($req) . " has stored (raw) conf $s" ); $res->{result} = 1; $res->{cfgNum} = $s; } else { $self->userLogger->notice( 'Raw saving attempt rejected, asking for confirmation to ' - . $self->userId($req) ); + . $self->p->userId($req) ); $res->{result} = 0; $res->{needConfirm} = 1 if ( $s == CONFIG_WAS_CHANGED ); $res->{message} .= '__needConfirmation__'; @@ -359,7 +336,7 @@ sub applyConf { my $status; # 1 Apply conf locally - $self->api->checkConf(); + $self->p->api->checkConf(); # Get apply section values my %reloadUrls = diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm index efe547886..e3dc85cf2 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm @@ -1156,8 +1156,6 @@ sub _unitTest { if ( $key =~ /^(?:$simpleHashKeys|$doubleHashKeys)$/o or $attr->{type} =~ /Container$/ ) { - my $keyMsg = $attr->{keyMsgFail} // $type->{keyMsgFail}; - my $msg = $attr->{msgFail} // $type->{msgFail}; $res = 0 unless ( $self->_execTest( { diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Notifications.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Notifications.pm index 71cd53d18..2f3209dab 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Notifications.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Notifications.pm @@ -13,7 +13,8 @@ require Lemonldap::NG::Common::Notifications; use feature 'state'; -extends 'Lemonldap::NG::Common::Conf::AccessLib'; +extends 'Lemonldap::NG::Manager::Plugin', + 'Lemonldap::NG::Common::Conf::AccessLib'; our $VERSION = '2.0.7'; @@ -26,7 +27,7 @@ has notifFormat => ( is => 'rw' ); use constant defaultRoute => 'notifications.html'; -sub addRoutes { +sub init { my ( $self, $conf ) = @_; if ( $conf->{oldNotifFormat} ) { @@ -74,6 +75,7 @@ sub addRoutes { { done => { ':notificationId' => 'deleteDoneNotification' } }, ['DELETE'] ); + return 1; } sub setNotifAccess { diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Plugin.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Plugin.pm new file mode 100644 index 000000000..28e6ef031 --- /dev/null +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Plugin.pm @@ -0,0 +1,51 @@ +package Lemonldap::NG::Manager::Plugin; + +use strict; +use Mouse; +our $VERSION = '2.0.6'; + +extends 'Lemonldap::NG::Common::Module'; + +has _confAcc => ( + is => 'rw', + lazy => 1, + default => sub { return $_[0]->p->{_confAcc} }, +); + +sub sendError { + my $self = shift; + return $self->p->sendError(@_); +} + +sub sendJSONresponse { + my $self = shift; + return $self->p->sendJSONresponse(@_); +} + +sub addRoute { + my ( $self, $word, $subName, $methods, $transform ) = @_; + $transform //= sub { + my ($sub) = @_; + if ( ref $sub ) { + return sub { + shift; + return $sub->( $self, @_ ); + } + } + else { + return sub { + shift; + return $self->$sub(@_); + } + } + }; + $self->p->addRoute( $word, $subName, $methods, $transform ); + return $self; +} + +sub loadTemplate { + my $self = shift; + return $self->p->loadTemplate(@_); +} + +1; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Sessions.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Sessions.pm index b09e58f56..bea703930 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Sessions.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Sessions.pm @@ -14,7 +14,8 @@ use Lemonldap::NG::Common::IPv6; use feature 'state'; -extends 'Lemonldap::NG::Common::Conf::AccessLib', +extends 'Lemonldap::NG::Manager::Plugin', + 'Lemonldap::NG::Common::Conf::AccessLib', 'Lemonldap::NG::Common::Session::REST'; our $VERSION = '2.0.4'; @@ -25,7 +26,7 @@ our $VERSION = '2.0.4'; use constant defaultRoute => 'sessions.html'; -sub addRoutes { +sub init { my ( $self, $conf ) = @_; # HTML template @@ -55,6 +56,7 @@ sub addRoutes { $self->{multiValuesSeparator} ||= '; '; $self->{impersonationPrefix} = $conf->{impersonationPrefix} || 'real_'; $self->{hiddenAttributes} //= "_password"; + return 1; } ####################### @@ -98,7 +100,7 @@ sub sessions { or return $self->sendError( $req, undef, 400 ); my $params = $req->parameters(); my $type = delete $params->{sessionType}; - $type = $type eq 'global' ? 'SSO' : ucfirst($type); + $type = $type eq 'global' ? 'SSO' : ucfirst($type); $type = $type eq 'Offline' ? 'OIDCI' : ucfirst($type); my $res; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Viewer.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Viewer.pm index 7e0fb5434..c0e5af369 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Viewer.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Viewer.pm @@ -11,6 +11,9 @@ use feature 'state'; extends 'Lemonldap::NG::Manager::Conf'; +has diffRule => ( is => 'rw', default => sub { 0 } ); +has brwRule => ( is => 'rw', default => sub { 0 } ); + our $VERSION = '2.0.6'; ############################# @@ -21,11 +24,36 @@ use constant defaultRoute => 'viewer.html'; has ua => ( is => 'rw' ); -sub addRoutes { +sub init { my ( $self, $conf ) = @_; $self->ua( Lemonldap::NG::Common::UserAgent->new($conf) ); + my $hd = "Lemonldap::NG::Handler::PSGI::Main"; - my $hiddenKeys = $self->{viewerHiddenKeys} || ''; + # Parse Diff activation rule + $conf->{viewerAllowDiff} //= 0; + $self->logger->debug( + "Diff activation rule -> " . ( $conf->{viewerAllowDiff} ) ); + my $rule = $hd->buildSub( $hd->substitute( $conf->{viewerAllowDiff} ) ); + unless ($rule) { + $self->logger->error( + "Bad Diff activation rule -> " . $hd->tsv->{jail}->error ); + return 0; + } + $self->diffRule($rule); + + # Parse Browser activation rule + $conf->{viewerAllowBrowser} //= 0; + $self->logger->debug( + "Browser activation rule -> " . ( $conf->{viewerAllowBrowser} ) ); + $rule = $hd->buildSub( $hd->substitute( $conf->{viewerAllowBrowser} ) ); + unless ($rule) { + $self->logger->error( + "Bad Browser activation rule -> " . $hd->tsv->{jail}->error ); + return 0; + } + $self->brwRule($rule); + + my $hiddenKeys = $conf->{viewerHiddenKeys} || ''; my @enabledKeys = (); my @keys = qw(virtualHosts samlIDPMetaDataNodes samlSPMetaDataNodes applicationList oidcOPMetaDataNodes oidcRPMetaDataNodes @@ -67,6 +95,7 @@ sub addRoutes { # Other keys ->addRoute( view => { ':cfgNum' => { '*' => 'viewKey' } }, ['GET'] ); + return 1; } sub getConfByNum { diff --git a/lemonldap-ng-manager/t/12-save-changed-conf.t b/lemonldap-ng-manager/t/12-save-changed-conf.t index b18bae0a3..703758f77 100644 --- a/lemonldap-ng-manager/t/12-save-changed-conf.t +++ b/lemonldap-ng-manager/t/12-save-changed-conf.t @@ -25,7 +25,7 @@ ok( $resBody = from_json( $res->[2]->[0] ), "Result body contains JSON text" ); ok( $resBody->{result} == 1, "JSON response contains \"result:1\"" ) or print STDERR Dumper($resBody); ok( - @{ $resBody->{details}->{__warnings__} } == 2, + $resBody->{details}->{__warnings__} and @{ $resBody->{details}->{__warnings__} } == 2, 'JSON response contains 2 warnings' ) or print STDERR Dumper($resBody); @@ -38,7 +38,7 @@ foreach my $i ( 0 .. 1 ) { } ok( - @{ $resBody->{details}->{__changes__} } == 24, + $resBody->{details}->{__changes__} and @{ $resBody->{details}->{__changes__} } == 24, 'JSON response contains 24 changes' ) or print STDERR Dumper($resBody); ok( diff --git a/lemonldap-ng-manager/t/70-viewer.t b/lemonldap-ng-manager/t/70-viewer.t index fa9c78d81..6feac406e 100644 --- a/lemonldap-ng-manager/t/70-viewer.t +++ b/lemonldap-ng-manager/t/70-viewer.t @@ -9,6 +9,9 @@ require 't/test-lib.pm'; my $struct = 't/jsonfiles/70-diff.json'; +# Remove new conf +unlink 't/conf/lmConf-2.json'; + sub body { return IO::File->new( $struct, 'r' ); } @@ -23,13 +26,13 @@ $res = &client->jsonResponse('/view/1/portalDisplayLogout'); ok( $res->{value} eq '_Hidden_', 'Key is hidden' ) or explain( $res, 'value => "_Hidden_"' ); $res = &client->jsonResponse('/view/1/samlIDPMetaDataNodes'); -ok( $res->{value} eq '_Hidden_', 'Key is hidden' ) +ok( ref($res) eq 'HASH' and $res->{value} eq '_Hidden_', 'Key is hidden' ) or explain( $res, 'value => "_Hidden_"' ); count(2); # Try to display latest conf $res = &client->jsonResponse('/view/latest'); -ok( $res->{cfgNum} eq '1', 'Latest conf loaded' ); +ok( $res->{cfgNum} eq '1', 'Latest conf loaded' ) or explain($res,"cfgNum => 1"); count(1); ok( @@ -57,9 +60,7 @@ $res = &client->jsonResponse('/view/diff/1/2'); # ok( $res->[1]->{captcha_login_enabled} eq '1', 'Key found' ); ok( $res->[1]->{captcha_mail_enabled} eq '0', 'Key found' ); -ok( 6 == keys %{ $res->[1] }, 'Right number of keys found' ) - or print STDERR Dumper($res); -count(2); +count(1); # Try to display previous conf $res = &client->jsonResponse('/view/1'); @@ -68,7 +69,7 @@ ok( $res->{cfgNum} eq '1', 'Browser is allowed' ) count(1); # Remove new conf -`rm -rf t/conf/lmConf-2.json`; +unlink 't/conf/lmConf-2.json'; done_testing( count() ); From 0ae1e81fceb9d9c4e17becde5c297f96372189ee Mon Sep 17 00:00:00 2001 From: Xavier Guimard Date: Tue, 28 Jan 2020 16:27:06 +0100 Subject: [PATCH 02/94] Update tr --- .../site/htdocs/static/languages/ar.json | 6 +++--- .../site/htdocs/static/languages/de.json | 6 +++--- .../site/htdocs/static/languages/it.json | 14 +++++++------- .../site/htdocs/static/languages/tr.json | 16 ++++++++-------- .../site/htdocs/static/languages/vi.json | 6 +++--- .../site/htdocs/static/languages/zh.json | 6 +++--- .../site/htdocs/static/languages/ar.json | 4 ++-- .../site/htdocs/static/languages/de.json | 2 +- .../site/htdocs/static/languages/es.json | 4 ++-- .../site/htdocs/static/languages/fi.json | 2 +- .../site/htdocs/static/languages/it.json | 8 ++++---- .../site/htdocs/static/languages/nl.json | 2 +- .../site/htdocs/static/languages/pt.json | 2 +- .../site/htdocs/static/languages/ro.json | 2 +- .../site/htdocs/static/languages/tr.json | 12 ++++++------ .../site/htdocs/static/languages/vi.json | 4 ++-- .../site/htdocs/static/languages/zh.json | 2 +- .../site/templates/common/mail/ar.json | 2 +- .../site/templates/common/mail/fi.json | 2 +- .../site/templates/common/mail/it.json | 2 +- .../site/templates/common/mail/ms.json | 1 + .../site/templates/common/mail/tr.json | 1 + .../site/templates/common/mail/vi.json | 2 +- .../site/templates/common/mail/zh_CN.json | 2 +- 24 files changed, 56 insertions(+), 54 deletions(-) diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/ar.json b/lemonldap-ng-manager/site/htdocs/static/languages/ar.json index b651fd71a..e7469f083 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/ar.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/ar.json @@ -175,7 +175,7 @@ "corsAllow_Origin":"Access-Control-Allow-Origin", "corsExpose_Headers":"Access-Control-Expose-Headers", "corsMax_Age":"Access-Control-Max-Age", -"cfgLog":"استئنف", +"cfgLog":"Summary", "cfgVersion":"عملية ضبط الإصدارات", "checkXSS":"تحقق من هجمات XSS", "clickHereToForce":"انقر هنا لإجبار", @@ -799,7 +799,7 @@ "saveReport":"احفظ التقرير", "savingConfirmation":"حفظ التأكيد", "scope":"نطاق", -"search":"Search ...", +"search":"Search...", "secondFactors":"Second factors", "securedCookie":"ملفات تعريف الارتباط المضمونة (سسل)", "security":"الحماية", @@ -1109,4 +1109,4 @@ "samlRelayStateTimeout":"تناوب حالة مهلة الجلسة ", "samlUseQueryStringSpecific":"استخدام أسلوب query_string المعين", "samlOverrideIDPEntityID":"Override Entity ID when acting as IDP" -} +} \ No newline at end of file diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/de.json b/lemonldap-ng-manager/site/htdocs/static/languages/de.json index c4c5770e3..af6f46546 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/de.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/de.json @@ -175,7 +175,7 @@ "corsAllow_Origin":"Access-Control-Allow-Origin", "corsExpose_Headers":"Access-Control-Expose-Headers", "corsMax_Age":"Access-Control-Max-Age", -"cfgLog":"Resume", +"cfgLog":"Summary", "cfgVersion":"Configuration version", "checkXSS":"Check XSS attacks", "clickHereToForce":"Click here to force", @@ -799,7 +799,7 @@ "saveReport":"Save report", "savingConfirmation":"Saving confirmation", "scope":"Scope", -"search":"Search ...", +"search":"Search...", "secondFactors":"Second factors", "securedCookie":"Secured Cookie (SSL)", "security":"Security", @@ -1109,4 +1109,4 @@ "samlRelayStateTimeout":"RelayState session timeout", "samlUseQueryStringSpecific":"Use specific query_string method", "samlOverrideIDPEntityID":"Override Entity ID when acting as IDP" -} +} \ No newline at end of file diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/it.json b/lemonldap-ng-manager/site/htdocs/static/languages/it.json index 03d777ed2..35dc784d8 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/it.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/it.json @@ -145,14 +145,14 @@ "certificateMailContent":"Certificate mail content", "certificateResetByMailManagement":"Certificate management", "certificateResetByMailURL":"Reset page URL", -"certificateResetByMailCeaAttribute":"Certificat CEA attribut", +"certificateResetByMailCeaAttribute":"Certificate CEA attibute", "certificateResetByMailCertificateAttribute":"Certificate attribute name", "certificateResetByMailStep1Subject":"Reset mail subject", "certificateResetByMailStep1Body":"Reset mail content", -"certificateResetByMailStep2Subject":"Confirmation mail subject", +"certificateResetByMailStep2Subject":"Soggetto della mail di conferma", "certificateResetByMailStep2Body":"Confirmation mail content", "certificateResetByMailValidityDelay":"Minimum duration before expiration", -"portalDisplayCertificateResetByMail":"Reset your crtificate", +"portalDisplayCertificateResetByMail":"Reset your certificate", "contentSecurityPolicy":"Politica di protezione dei contenuti", "contextSwitching":"Switch context another user", "contextSwitchingHiddenAttributes":"Attributi nascosti", @@ -175,7 +175,7 @@ "corsAllow_Origin":"Access-Control-Allow-Origin", "corsExpose_Headers":"Access-Control-Expose-Headers", "corsMax_Age":"Access-Control-Max-Age", -"cfgLog":"Riprendi", +"cfgLog":"Summary", "cfgVersion":"Versione configurazione", "checkXSS":"Verifica attacchi XSS", "clickHereToForce":"Clicca qui per forzare", @@ -457,7 +457,7 @@ "mailCharset":"Charset", "mailConfirmBody":"Contenuto della mail di conferma", "mailConfirmSubject":"Soggetto della mail di conferma", -"mailContent":"Contenuto della mail di ripristino della password", +"mailContent":"Password mail content", "mailFrom":"Mittente", "mailHeaders":"Intestazioni di posta", "mailLDAPFilter":"Filtro mail", @@ -799,7 +799,7 @@ "saveReport":"Salva report", "savingConfirmation":"Salvataggio della conferma", "scope":"Ambito", -"search":"Cerca ...", +"search":"Cerca...", "secondFactors":"Secondi fattori", "securedCookie":"Cookie protetti (SSL)", "security":"Sicurezza", @@ -1109,4 +1109,4 @@ "samlRelayStateTimeout":"Timeout di sessione di RelayState", "samlUseQueryStringSpecific":"Utilizza il metodo specifico query_string", "samlOverrideIDPEntityID":"Sostituisci l'ID entità quando agisce come IDP" -} +} \ No newline at end of file diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/tr.json b/lemonldap-ng-manager/site/htdocs/static/languages/tr.json index d9fc3e902..fdb288249 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/tr.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/tr.json @@ -144,13 +144,13 @@ "cda":"Çoklu alan adları", "certificateMailContent":"Certificate mail content", "certificateResetByMailManagement":"Certificate management", -"certificateResetByMailURL":"Reset page URL", +"certificateResetByMailURL":"Sayfa URL'sini sıfırla", "certificateResetByMailCeaAttribute":"Certificate CEA attibute", "certificateResetByMailCertificateAttribute":"Certificate attribute name", "certificateResetByMailStep1Subject":"Reset mail subject", "certificateResetByMailStep1Body":"Reset mail content", -"certificateResetByMailStep2Subject":"Confirmation mail subject", -"certificateResetByMailStep2Body":"Confirmation mail content", +"certificateResetByMailStep2Subject":"Doğrulama e-postası konusu", +"certificateResetByMailStep2Body":"Doğrulama e-postası içeriği", "certificateResetByMailValidityDelay":"Minimum duration before expiration", "portalDisplayCertificateResetByMail":"Reset your certificate", "contentSecurityPolicy":"İçerik güvenlik ilkesi", @@ -175,7 +175,7 @@ "corsAllow_Origin":"Access-Control-Allow-Origin", "corsExpose_Headers":"Access-Control-Expose-Headers", "corsMax_Age":"Access-Control-Max-Age", -"cfgLog":"Sürdür", +"cfgLog":"Summary", "cfgVersion":"Yapılandırma sürümü", "checkXSS":"XSS saldırılarını kontrol et", "clickHereToForce":"Zorlamak için buraya tıklayın", @@ -457,7 +457,7 @@ "mailCharset":"Karakter seti", "mailConfirmBody":"Doğrulama e-postası içeriği", "mailConfirmSubject":"Doğrulama e-postası konusu", -"mailContent":"Parola sıfırlama e-postası içeriği", +"mailContent":"Password mail content", "mailFrom":"E-posta göndericisi", "mailHeaders":"E-posta başlıkları", "mailLDAPFilter":"E-posta filtresi", @@ -671,7 +671,7 @@ "passwordDB":"Parola modülü", "passwordManagement":"Parola yönetimi", "passwordPolicyMinSize":"Minimum parola uzunluğu", -"passwordPolicyMinLower":"Minimum küçük harf karakter sayısı:", +"passwordPolicyMinLower":"Minimum küçük harf karakter sayısı", "passwordPolicyMinUpper":"Minimum büyük harf karakter sayısı", "passwordPolicyMinDigit":"Minimum rakam karakter sayısı", "passwordResetAllowedRetries":"Maksimum parola sıfırlama denemesi", @@ -799,7 +799,7 @@ "saveReport":"Raporu kaydet", "savingConfirmation":"Doğrulama kaydediliyor", "scope":"Kapsam", -"search":"Ara ...", +"search":"Ara...", "secondFactors":"İki faktörlü kimlik doğrulama", "securedCookie":"Güvenli Çerez (SSL)", "security":"Güvenlik", @@ -1109,4 +1109,4 @@ "samlRelayStateTimeout":"RelayState oturum zaman aşımı", "samlUseQueryStringSpecific":"Spesifik query_string metodu kullan", "samlOverrideIDPEntityID":"IDP olarak davrandığında Varlık ID'yi geçersiz kıl" -} +} \ No newline at end of file diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/vi.json b/lemonldap-ng-manager/site/htdocs/static/languages/vi.json index 4f7141e12..98081bc2e 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/vi.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/vi.json @@ -175,7 +175,7 @@ "corsAllow_Origin":"Access-Control-Allow-Origin", "corsExpose_Headers":"Access-Control-Expose-Headers", "corsMax_Age":"Access-Control-Max-Age", -"cfgLog":"Tiếp tục", +"cfgLog":"Summary", "cfgVersion":"Phiên bản cấu hình", "checkXSS":"Kiểm tra tấn công XSS", "clickHereToForce":"Nhấp vào đây để bắt buộc", @@ -799,7 +799,7 @@ "saveReport":"Lưu báo cáo", "savingConfirmation":"Lưu xác nhận", "scope":"Phạm vi", -"search":"Search ...", +"search":"Search...", "secondFactors":"Second factors", "securedCookie":"Cookie bảo mật (SSL)", "security":"An ninh", @@ -1109,4 +1109,4 @@ "samlRelayStateTimeout":"Thời gian hết hạn phiên RelayState ", "samlUseQueryStringSpecific":"Sử dụng phương pháp query_string cụ thể", "samlOverrideIDPEntityID":"Override Entity ID when acting as IDP" -} +} \ No newline at end of file diff --git a/lemonldap-ng-manager/site/htdocs/static/languages/zh.json b/lemonldap-ng-manager/site/htdocs/static/languages/zh.json index ce757d4f2..67bbabc2d 100644 --- a/lemonldap-ng-manager/site/htdocs/static/languages/zh.json +++ b/lemonldap-ng-manager/site/htdocs/static/languages/zh.json @@ -175,7 +175,7 @@ "corsAllow_Origin":"Access-Control-Allow-Origin", "corsExpose_Headers":"Access-Control-Expose-Headers", "corsMax_Age":"Access-Control-Max-Age", -"cfgLog":"档案", +"cfgLog":"Summary", "cfgVersion":"配置信息", "checkXSS":"Check XSS attacks", "clickHereToForce":"Click here to force", @@ -799,7 +799,7 @@ "saveReport":"Save report", "savingConfirmation":"Saving confirmation", "scope":"Scope", -"search":"Search ...", +"search":"Search...", "secondFactors":"Second factors", "securedCookie":"Secured Cookie (SSL)", "security":"Security", @@ -1109,4 +1109,4 @@ "samlRelayStateTimeout":"RelayState session timeout", "samlUseQueryStringSpecific":"Use specific query_string method", "samlOverrideIDPEntityID":"Override Entity ID when acting as IDP" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/ar.json b/lemonldap-ng-portal/site/htdocs/static/languages/ar.json index e9dcb036e..3de27c194 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/ar.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/ar.json @@ -199,7 +199,7 @@ "notFound":"لم يتم العثور: محاولة الدخول إلى صفحة غير متوفرة", "noTOTPFound":"No TOTP found", "noU2FKeyFound":"No U2F key found", -"oidcConsent":"The application %s would like to:", +"oidcConsent":"التطبيق ٪s هل ترغب في معرفة:", "oidcConsents":"OIDC consents", "oidcConsentsFull":"OpenID Connect consents", "oneExpired2Fremoved":"An expired 2F device has been removed!", @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Your TOTP key", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/de.json b/lemonldap-ng-portal/site/htdocs/static/languages/de.json index 0a6415c91..00b173c79 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/de.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/de.json @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Your TOTP key", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/es.json b/lemonldap-ng-portal/site/htdocs/static/languages/es.json index d229e78c5..5e32d5a16 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/es.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/es.json @@ -165,7 +165,7 @@ "gplSoft":"Software libre cubierto bajo licencia GPL", "groups_sso":"GRUPOS SSO", "headers":"ENCABEZADOS", -"hello":"Buesnos dias", +"hello":"Hello", "id":"Id", "imSure":"Estoy seguro", "info":"Información", @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Su llave TOTP", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/fi.json b/lemonldap-ng-portal/site/htdocs/static/languages/fi.json index 6748754a9..fdc4ea7d7 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/fi.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/fi.json @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Your TOTP key", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/it.json b/lemonldap-ng-portal/site/htdocs/static/languages/it.json index d3051dfcf..a35834f0d 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/it.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/it.json @@ -124,7 +124,7 @@ "choose2f":"Scegli il tuo secondo fattore", "chooseApp":"Scegli un'applicazione alla quale ti è consentito l'accesso", "cipheredValue":"Ciphered value", -"click2Reset":"Click here to reset your password", +"click2Reset":"Clicca qui per reimpostare la password", "click2ResetCertificate":"Click here to reset your certificate", "clickHere":"Per favore clicka qui", "clickOnYubikey":"Clicca sulla tua Yubikey", @@ -165,7 +165,7 @@ "gplSoft":"Software libero coperto dalla licenza GPL", "groups_sso":"GRUPPI SSO", "headers":"INTESTAZIONI", -"hello":"Buongiorno", +"hello":"Salve", "id":"Id", "imSure":"Sono sicuro", "info":"Informazioni", @@ -199,7 +199,7 @@ "notFound":"Non trovato: si tenta di accedere ad una pagina non disponibile", "noTOTPFound":"Nessun TOTP trovato", "noU2FKeyFound":"Nessuna chiave U2F trovata", -"oidcConsent":"The application %s would like to:", +"oidcConsent":"L'applicazione %s vorrebbe sapere:", "oidcConsents":"Consensi OIDC", "oidcConsentsFull":"Consensi OpenID Connect", "oneExpired2Fremoved":"An expired 2F device has been removed!", @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"La tua chiave TOTP", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/nl.json b/lemonldap-ng-portal/site/htdocs/static/languages/nl.json index 389ffc77d..3bc65beee 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/nl.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/nl.json @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Your TOTP key", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/pt.json b/lemonldap-ng-portal/site/htdocs/static/languages/pt.json index 5d32f61dd..770232fed 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/pt.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/pt.json @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Your TOTP key", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/ro.json b/lemonldap-ng-portal/site/htdocs/static/languages/ro.json index 9f667b24f..7edfe875a 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/ro.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/ro.json @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Your TOTP key", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/tr.json b/lemonldap-ng-portal/site/htdocs/static/languages/tr.json index 7e298414f..9f6282b25 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/tr.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/tr.json @@ -86,9 +86,9 @@ "PE94":"Gerekli bir nitelik mevcut değil", "PE95":"DECRYPT servisine erişime izin verilmedi", "PE96":"Geçersiz doğrulama kodu", -"PE97":"Please select your new certificate", +"PE97":"Your certificate is invalid or expires soon", "PE98":"Please select your new certificate", -"PE99":"Your certificate is invalid or expires soon", +"PE99":"Please select your new certificate", "2fRegRequired":"Bu servis iki adımlı kimlik doğrulama gerektiriyor. Şimdi bir cihaz ekleyin ve ardından portala geri dönün", "accept":"Kabul Et", "accessDenied":"Bu uygulamaya erişim yetkiniz yok", @@ -124,7 +124,7 @@ "choose2f":"İkinci faktörünüzü seçin", "chooseApp":"Erişim yetkiniz olan bir uygulama seçin", "cipheredValue":"Şifrelenmiş değer", -"click2Reset":"Click here to reset your password", +"click2Reset":"Parolanızı sıfırlamak için buraya tıklayın", "click2ResetCertificate":"Click here to reset your certificate", "clickHere":"Lütfen buraya tıklayın", "clickOnYubikey":"Yubikey'e tıklayın", @@ -165,7 +165,7 @@ "gplSoft":"GPL lisansı kapsamında özgür yazılım", "groups_sso":"TOA GRUPLARI", "headers":"BAŞLIKLAR", -"hello":"Hello", +"hello":"Merhaba", "id":"ID", "imSure":"Eminim", "info":"Bilgi", @@ -216,7 +216,7 @@ "passwordPolicyMinSize":"Minimum parola uzunluğu", "passwordPolicyMinLower":"Minimum küçük harf karakter sayısı:", "passwordPolicyMinUpper":"Minimum büyük harf karakter sayısı:", -"passwordPolicyMinDigit":"Minimum rakam karakter sayısı", +"passwordPolicyMinDigit":"Minimum rakam karakter sayısı:", "ppGrace":"kimlik doğrulaması kaldı, parolanızı değiştirin!", "proxyError":"Kötü ağ geçidi: uzak sunucuya katılamıyor", "pwd":"Parola", @@ -298,4 +298,4 @@ "yourProfile":"Profilini bil", "yourTotpKey":"TOTP anahtarınız", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/vi.json b/lemonldap-ng-portal/site/htdocs/static/languages/vi.json index 2c80d3869..9ee851115 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/vi.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/vi.json @@ -199,7 +199,7 @@ "notFound":"Không tìm thấy: bạn cố gắng truy cập vào một trang không có sẵn", "noTOTPFound":"Đăng xuất khỏi các ứng dụng khác", "noU2FKeyFound":"No U2F key found", -"oidcConsent":"The application %s would like to:", +"oidcConsent":"Ứng dụng %s muốn biết:", "oidcConsents":"OIDC consents", "oidcConsentsFull":"OpenID Connect consents", "oneExpired2Fremoved":"An expired 2F device has been removed!", @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Your TOTP key", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/zh.json b/lemonldap-ng-portal/site/htdocs/static/languages/zh.json index 0e21fdd04..8294af50d 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/zh.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/zh.json @@ -298,4 +298,4 @@ "yourProfile":"Know your profile", "yourTotpKey":"Your TOTP key", "yubikey2f":"Yubikey" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/templates/common/mail/ar.json b/lemonldap-ng-portal/site/templates/common/mail/ar.json index 21049c384..7ced67e83 100644 --- a/lemonldap-ng-portal/site/templates/common/mail/ar.json +++ b/lemonldap-ng-portal/site/templates/common/mail/ar.json @@ -16,4 +16,4 @@ "requestIssuedFromIP":"الطلب قد أرسل من عنوان الآي بي", "yourLoginCodeIs":"Your login code is", "yourLoginIs":"تسجيل الدخول الخاص بك هو" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/templates/common/mail/fi.json b/lemonldap-ng-portal/site/templates/common/mail/fi.json index c43304b57..847e7f106 100644 --- a/lemonldap-ng-portal/site/templates/common/mail/fi.json +++ b/lemonldap-ng-portal/site/templates/common/mail/fi.json @@ -16,4 +16,4 @@ "requestIssuedFromIP":"The request was issued from IP", "yourLoginCodeIs":"Your login code is", "yourLoginIs":"Your login is" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/templates/common/mail/it.json b/lemonldap-ng-portal/site/templates/common/mail/it.json index 6545cf568..d3fd9f331 100644 --- a/lemonldap-ng-portal/site/templates/common/mail/it.json +++ b/lemonldap-ng-portal/site/templates/common/mail/it.json @@ -16,4 +16,4 @@ "requestIssuedFromIP":"La richiesta è stata emessa da IP", "yourLoginCodeIs":"Il tuo codice di accesso è", "yourLoginIs":"Il tuo login é" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/templates/common/mail/ms.json b/lemonldap-ng-portal/site/templates/common/mail/ms.json index a76f99514..ebc443571 100644 --- a/lemonldap-ng-portal/site/templates/common/mail/ms.json +++ b/lemonldap-ng-portal/site/templates/common/mail/ms.json @@ -1,4 +1,5 @@ { +"resetCertificat":"Your certificate was reset", "accountCreated":"Akaun anda telah dicipta, kata laluan sementara anda telah dihantar ke alamat emel anda.", "autoMail":"Emel ini telah dihantar secara automatik", "click2Register":"Klik di sini untuk mengesahkan akaun anda", diff --git a/lemonldap-ng-portal/site/templates/common/mail/tr.json b/lemonldap-ng-portal/site/templates/common/mail/tr.json index 9f2aded84..48cbd436d 100644 --- a/lemonldap-ng-portal/site/templates/common/mail/tr.json +++ b/lemonldap-ng-portal/site/templates/common/mail/tr.json @@ -1,4 +1,5 @@ { +"resetCertificat":"Your certificate was reset", "accountCreated":"Hesabınız oluşturuldu, geçici parolanız e-posta adresinize gönderildi.", "autoMail":"Bu e-posta otomatik olarak gönderilmiştir", "click2Register":"Hesap açma işleminizi onaylamak için buraya tıklayın", diff --git a/lemonldap-ng-portal/site/templates/common/mail/vi.json b/lemonldap-ng-portal/site/templates/common/mail/vi.json index f6d45809e..d73a85ec3 100644 --- a/lemonldap-ng-portal/site/templates/common/mail/vi.json +++ b/lemonldap-ng-portal/site/templates/common/mail/vi.json @@ -16,4 +16,4 @@ "requestIssuedFromIP":"Yêu cầu được gửi đi từ địa chỉ IP", "yourLoginCodeIs":"Your login code is", "yourLoginIs":"Đăng nhập của bạn là" -} +} \ No newline at end of file diff --git a/lemonldap-ng-portal/site/templates/common/mail/zh_CN.json b/lemonldap-ng-portal/site/templates/common/mail/zh_CN.json index 8eff6297e..fdec39b3c 100644 --- a/lemonldap-ng-portal/site/templates/common/mail/zh_CN.json +++ b/lemonldap-ng-portal/site/templates/common/mail/zh_CN.json @@ -16,4 +16,4 @@ "requestIssuedFromIP":"此请求来自IP地址", "yourLoginCodeIs":"Your login code is", "yourLoginIs":"您登陆的账户是" -} +} \ No newline at end of file From a5c97cd74590d7ada731c584efd55861d0e06ecf Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 28 Jan 2020 13:02:04 +0100 Subject: [PATCH 03/94] ConfigParser: return parsing errors in global message (#1902) --- lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm index efe547886..a1f808e9c 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm @@ -51,7 +51,10 @@ has changes => ( is => 'rw', isa => 'ArrayRef', default => sub { return [] } ); has message => ( is => 'rw', isa => 'Str', - default => '', + lazy => 1, + default => sub { + return join( ', ', map { $_->{message} } @{ $_[0]->errors } ); + }, trigger => sub { hdebug( "Message becomes " . $_[0]->{message} ); } From 106634bbcdc9f468febecc5fc2098ccc35c5708d Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Wed, 29 Jan 2020 08:44:51 +0100 Subject: [PATCH 04/94] Improve llng-cli doc (#1902) --- lemonldap-ng-common/scripts/lemonldap-ng-cli | 39 ++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lemonldap-ng-common/scripts/lemonldap-ng-cli b/lemonldap-ng-common/scripts/lemonldap-ng-cli index 8dd638d74..e95b99a6f 100755 --- a/lemonldap-ng-common/scripts/lemonldap-ng-cli +++ b/lemonldap-ng-common/scripts/lemonldap-ng-cli @@ -51,6 +51,13 @@ Available actions: - restore - : import configuration from STDIN - restore : import configuration from file +Options: + - yes <0|1> : accept confirmation prompt automatically + - log : set configuration log message + - safe <0|1> : fail in case the requested configuration is invalid + - force <0|1> : allow overwrite of existing config number + - cfgNum : set new configuration number (requires -force 1) + See Lemonldap::NG::Manager::Cli(3) for more }; } @@ -92,6 +99,12 @@ Set some values # add or set a key $ lemonldap-ng-cli addKey macro fullname '$givenName." ".$lastName' + # without changing the version number + $ lemonldap-ng-cli -force 1 -cfgNum 1 set portal http://auth.e.com/ domain e.com + + # without asking for confirmation + $ lemonldap-ng-cli -yes 1 set portal http://auth.e.com/ domain e.com + =head1 DESCRIPTION lemonldap-ng-cli is a command line interface to interact with Lemonldap::NG @@ -120,6 +133,32 @@ and L =back +=head2 Available options + +=over + +=item -yes + +Confirm modification automatically (default: 0) + +=item -log + +Allows you to set the log message that will be displayed in the manager + +=item -safe + +The configuration change will be aborted if it contains errors (default: 0) + +=item -cfgNum + +Choose a particular configuration number (default: latest) + +=item -force + +Allows you to force overwriting an existing configuration (default: 0) + +=back + =head1 SEE ALSO L, L From 875495c478dd9e184decc66079c1f7d316f3c596 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Wed, 29 Jan 2020 08:45:06 +0100 Subject: [PATCH 05/94] lemonldap-ng-cli: add safe option (#1902) --- lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm index be6662bd9..dba30a0b9 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm @@ -26,6 +26,7 @@ has req => ( is => 'ro' ); has sep => ( is => 'rw', isa => 'Str', default => '/' ); has format => ( is => 'rw', isa => 'Str', default => "%-25s | %-25s | %-25s" ); has yes => ( is => 'rw', isa => 'Bool', default => 0 ); +has safe => ( is => 'rw', isa => 'Bool', default => 0 ); has force => ( is => 'rw', isa => 'Bool', default => 0 ); has logger => ( is => 'ro', lazy => 1, builder => sub { $_[0]->mgr->logger } ); has userLogger => @@ -277,9 +278,14 @@ sub _save { } ); unless ( $parser->testNewConf( $self->localConf ) ) { - $self->logger->error( - "CLI: Configuration rejected with message: $parser->{message}"); - printf STDERR "Modifications rejected: %s:\n", $parser->{message}; + my $msg = "Configuration rejected with message: " . $parser->message; + $self->logger->error("CLI: $msg"); + if ( $self->safe ) { + die "$msg"; + } + else { + print STDERR "$msg\n"; + } } my $saveParams = { force => $self->force }; if ( $self->force and $self->cfgNum ) { From f997a26e4156c9731a178c09aebd098e86038059 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Thu, 30 Jan 2020 20:43:04 +0100 Subject: [PATCH 06/94] Fix form method when displaying info in autoPost (#2080) --- .../lib/Lemonldap/NG/Portal/Main/Display.pm | 3 +- .../lib/Lemonldap/NG/Portal/Main/Run.pm | 2 +- ...-Auth-and-issuer-SAML-Redirect-With-Info.t | 398 ++++++++++++++++++ 3 files changed, 401 insertions(+), 2 deletions(-) create mode 100644 lemonldap-ng-portal/t/30-Auth-and-issuer-SAML-Redirect-With-Info.t diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Display.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Display.pm index f50acfbdb..44e82334b 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Display.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Display.pm @@ -136,9 +136,10 @@ sub display { URL => $req->{urldc}, HIDDEN_INPUTS => $self->buildHiddenForm($req), ACTIVE_TIMER => $req->data->{activeTimer}, - FORM_METHOD => $self->conf->{infoFormMethod}, CHOICE_PARAM => $self->conf->{authChoiceParam}, CHOICE_VALUE => $req->data->{_authChoice}, + FORM_METHOD => $req->data->{infoFormMethod} + || $self->conf->{infoFormMethod}, ( $req->data->{customScript} ? ( CUSTOM_SCRIPT => $req->data->{customScript} ) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index 541292d7f..c4aa0151e 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -644,7 +644,7 @@ sub autoPost { # Display info before redirecting if ( $req->info() ) { - $req->{infoFormMethod} = $req->param('method') || "post"; + $req->data->{infoFormMethod} = $req->param('method') || "post"; return PE_INFO; } diff --git a/lemonldap-ng-portal/t/30-Auth-and-issuer-SAML-Redirect-With-Info.t b/lemonldap-ng-portal/t/30-Auth-and-issuer-SAML-Redirect-With-Info.t new file mode 100644 index 000000000..8df0e6ef3 --- /dev/null +++ b/lemonldap-ng-portal/t/30-Auth-and-issuer-SAML-Redirect-With-Info.t @@ -0,0 +1,398 @@ +use lib 'inc'; +use Test::More; +use strict; +use IO::String; +use LWP::UserAgent; +use LWP::Protocol::PSGI; +use MIME::Base64; + +BEGIN { + require 't/test-lib.pm'; + require 't/saml-lib.pm'; +} + +my $maintests = 10; +my $debug = 'error'; +my ( $issuer, $sp, $res ); +my %handlerOR = ( issuer => [], sp => [] ); + +# Redefine LWP methods for tests +LWP::Protocol::PSGI->register( + sub { + my $req = Plack::Request->new(@_); + fail('POST should not launch SOAP requests'); + count(1); + return [ 500, [], [] ]; + } +); + +SKIP: { + eval "use Lasso"; + if ($@) { + skip 'Lasso not found', $maintests; + } + + # Initialization + ok( $issuer = issuer(), 'Issuer portal' ); + $handlerOR{issuer} = \@Lemonldap::NG::Handler::Main::_onReload; + + # Do a user login to have an existing session + + my $res; + my $query = "user=french&password=french"; + ok( + $res = $issuer->_post( + '/', + IO::String->new($query), + accept => 'text/html', + length => length($query), + ), + 'Post authentication request' + ); + + expectCookie($res); + + switch ('sp'); + &Lemonldap::NG::Handler::Main::cfgNum( 0, 0 ); + + ok( $sp = sp(), 'SP portal' ); + $handlerOR{sp} = \@Lemonldap::NG::Handler::Main::_onReload; + + # Simple SP access + ok( + $res = $sp->_get( + '/', + accept => 'text/html', + query => 'url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29tLw==' + ), + 'Unauth SP request' + ); + my ( $host, $url ); + ( $url, $query ) = expectRedirection( $res, + qr#^http://auth.idp.com(/saml/singleSignOn)\?(SAMLRequest=.+)# ); + + # Push SAML request to IdP + switch ('issuer'); + ok( + $res = $issuer->_get( + $url, + query => $query, + accept => 'text/html', + ), + 'Launch SAML request to IdP' + ); + expectOK($res); + my $pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' ); + + # Try to authenticate + + my $body = $res->[2]->[0]; + $body =~ s/^.*?//s; + $body =~ s#.*$##s; + my %fields = + ( $body =~ /%, + 'Found info message about deleted sessions' + ); + + # Method should still be POST + ( $host, $url, $query ) = + expectAutoPost( $res, 'auth.sp.com', '/saml/proxySingleSignOnPost', + 'SAMLResponse', 'RelayState' ); + + # Post SAML response to SP + switch ('sp'); + ok( + $res = $sp->_post( + $url, IO::String->new($query), + accept => 'text/html', + length => length($query), + ), + 'Post SAML response to SP' + ); + my $spId = expectCookie($res); + expectRedirection( $res, 'http://test1.example.com/' ); + + ok( $res = $sp->_get( '/', cookie => "lemonldap=$spId" ), 'Get / on SP' ); + expectOK($res); + expectAuthenticatedAs( $res, 'fa@badwolf.org@idp' ); + +} + +count($maintests); +clean_sessions(); +done_testing( count() ); + +sub switch { + my $type = shift; + @Lemonldap::NG::Handler::Main::_onReload = @{ + $handlerOR{$type}; + }; +} + +sub issuer { + return LLNG::Manager::Test->new( { + ini => { + logLevel => $debug, + domain => 'idp.com', + portal => 'http://auth.idp.com', + authentication => 'Demo', + userDB => 'Same', + singleSession => 1, + issuersTimeout => 120, + issuerDBSAMLActivation => 1, + samlSPMetaDataOptions => { + 'sp.com' => { + samlSPMetaDataOptionsEncryptionMode => 'none', + samlSPMetaDataOptionsSignSSOMessage => 1, + samlSPMetaDataOptionsSignSLOMessage => 1, + samlSPMetaDataOptionsCheckSSOMessageSignature => 1, + samlSPMetaDataOptionsCheckSLOMessageSignature => 1, + } + }, + samlSPMetaDataExportedAttributes => { + 'sp.com' => { + cn => +'1;cn;urn:oasis:names:tc:SAML:2.0:attrname-format:basic', + uid => +'1;uid;urn:oasis:names:tc:SAML:2.0:attrname-format:basic', + } + }, + samlOrganizationDisplayName => "IDP", + samlOrganizationName => "IDP", + samlOrganizationURL => "http://www.idp.com/", + samlServicePrivateKeyEnc => "-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAnfKBDG/K0TnGT7Xu8q1N45sNWvIK91SqNg8nvN2uVeKoHADT +csus5Xn3id5+8Q9TuMFsW9kIEeXiaPKXQa9ryfSNDhWDWloNkpGEeWif2BnHUu46 +Abu1UBWb0mH6VwcG1PR4qHruLis1odjQ1qnVDNfSEASVIppEBYjDX203ypmURIzU +6h53GRRRlf1BLWkbVn9ysmDeR57Xw5Rsx/+tBlcnMrkv/40DSUkehQIl2JmlFrl2 +Caik+gU4pd20apA/pNLjBZF0OmGoS08AIR5NMd0KFa6CwZUUSHJqH5GFy5Y2yl4l +g8K0klAS9q7L7aXI+eFQZhkwidjpxXnHPyxIGQIDAQABAoIBAHnfqjX3eO8SfnP5 +NURp90Td2mNHirCn0qLd9NKl1ySMPR1GgeH9SQ7Umu32EcteAUL5dOw2PiTZVmeW +cKINgsWVftXUQcOQ4xIqWKb51QUBdy0FhxrZRSFjWxXt5iYK1PmzHfsax/g1/S9C +RnqtFyjOy1bywkSt9jiy+9YBR2B7BDhLHlILbijWn5zaecaV4YA+L1UK4M/mehdb ++0FVPavbGpnlqBRTY+7YXfZ/mRPCfn5DvO9lW1O0pJMmNdBh9kmm3DxHf6AkK47a +43gO/dRWiWo2rZ/+Jw7uyqOb23U0MydP7kia0p3tzCUBPsrlgnichYG5RNFp0wqy +3VT1TYECgYEA0Y9vENy1jJd+s7WbGrsRtSKxfZgtJr0yjSlQVYrIlwbZSGn+ndxq +V2vVlwIgLX3pz6T40BMfk6SNx08jjy0Sgn6OAM0ILrinno8yWcSAMCmfCU0S/3O1 +55bqtcnk4XTHBHzJ5OrnrPaW5ourvJz0lcWEKMg3BXxLzaF6ZRy85nECgYEAwPMD +LNAKLCDrUMyYFOpPyPLe7wvszcFvPipGgerSgFP1c6N7xaMUdHDYqBfuis1khPGF +YcMHeNBYmzX6yEGbp3lrB4PHpUySmTU3mv3u9I05aahInK21gXum3uRkCWyyIF6V +T/qeszl9mVOCp0CC4eG3IMVpaD0UKDEHVhERYCkCgYAjuTPRyA4a3Wh38ilysRkf +q75eDqcDx5Tqg3RyYKo5NK2troP9HSnzpSpQB8i8eI53G0RfFCN5479XjqIdMi3J +mRFUCZ+vd0L7wKVwsBK6Ix49U6o9adhElnGEc9pUpLeYiD1SjMjZr1+iBYVNLeRz +86vH1/mpMbsqXrCis/dvwQKBgGttomHr/w3s0jftget7PirrFrbP0+wHfDGHhjRF +kyhCFtJovrwefYALaIXGtVjw3LusYZA570oT7pGUb2naJZkMYEwR0jG1vZWx7KDO +K6JbkxDB0pPxn7JVL2bAkPYyX8boAohCSOQO6WBZ/8+xem3bp4OGhpa0EyoBik0g +OaVpAoGATj4SyYsE10hGT676iie8zy3fi5IPC3E+x4QlVuusaLtuY8LJA50stjtx +gUa/JAKlZZL+gvzvOviQIxyfIChXOdTt5uiOYkdHJDbAF3NSrji7hrXq4v8UZv75 +8hBrwJZIpy6y01dRlrriHmPRtEq1pk7JX2uUg0sP5g4BEcsaCbc= +-----END RSA PRIVATE KEY----- +", + samlServicePrivateKeySig => "-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAtR/wgDqWB4Maho5V6TjcL/NbNfjgIh7GcgkrB5RZcVT1GTej +JlMjUQdgBKBuZXQN+7/29P6UcGq1kYalURq6S8SpeJ1ofp5rBEoD/TIkvU0JOcid +65wp+fdzXGXsfiZvHraU74jSCgjP/wqfVGRyBIQzB0SIxSpnrsigqNsE1E94toDM +x4wovjHu/9ABAImREV7Sz83OeFF00/sghrjTEJOD/gHf04JCn9MgNOqvSTysr9LX +Wg/oUKQDEYeTq9ux6pq/oqv1MxwONbSZPtN5yD41mi+hT8Rh+W8Je8rsiML4VMxz +sb1l9303asw6suo5bLTISKNSbu1nt1NkpNxzywIDAQABAoIBAQCQkbvPPfP+bwC/ +IeEk1IO7qkzFWa7czR+safD0jc6OjTdNN4F716Q6yt4zEzLKu8VliiW+C23EBQiD +7asKf4DvdTun0ExVtHDK7aEdeealSlXwz1ZtdypyILbtq1UGo/rR0v4x601rQPl0 +IrBmFf6D6FkqleNtLJmxguXpoVfLdYKNwkxH2ux+GOA9r2o5pUCQmJGDap5YWRuQ +uB71ewJjVWujaL3e1ac/5cP7/tqWmgAiOaN8sYdD6+oWOR47bHj8JKcMBSl4y2QC +dL31cGmmf5KqBbtISki3RXfHHjT7E3Z85CbESkKTZlEb1ar3XmepY6Z7V5UO16oz +fFE5R6khAoGBAOl9Qb+qYVVO5ugE65ORjYVeuXykANhM9ssiY5a6zuAakWzw7Zv3 +k6PXm9p7azlEXAlTnTXVwHYMyuuzZDvQ8LRV1iBOdPuIkUAmaQ5K9ASD7VcoHexh +k8DAKf9Ln7sTRaMdvgceRNczOmJOBIEpTZkssA/jVGXZsoyTWYl1en/ZAoGBAMaW +RnNbSNprEV2b8UeAJ6i77c4SXwu1I8X2NLtiLScb1ETBjfrdHmdlJglfyd/0gmhH +p/43Ku2iGUoY5KtuOI6QmahrJYQscRQhoj252VXadG6fNWWAlpgdCm9houhHb5BF +3zge/bTr0anUe9EA7Z/ymav12rEouoNjIlhI9C5DAoGATR85a2SMt8/TB0owwdJu +62GpZNkLCmcJkXkvaecUVAOSi2hdI4o4MwMRkK35cbX5rH74y4JqCtQY5pefgP53 +sykzDAK+MyMdzxGg2764MRGegI5Yq+5jDmSquo+xF+q6srEtRk6iMG7UVwosBLmu +zuxqzySoiOfKSRKWnYe3SakCgYEAwWMkVkAmETXE4oDzFSsS8/mW2l//mPocTTK3 +JWe1CunJ6+8FYbAlZJEW2ngismp8+CoXybNVpbZ+pC7buKoMf6EHUgCNt0pEEFO0 +mCG9KSMk0XlPWXpArP9S4yaUq1itpzSz7QYZES+4rIcU0HLz9RgeWFyCTJWaFErc +7laVG9sCgYBKOtk5WlIOP4BxSd2y4cYzohgwTZIs1/2kTEn1u4eH73M1xvAlHHFB +wSF5QXgDKJ8pPAOhNWpdLO/PdtnQn91nOvTNc+ShJZzjdbneUdQVpWpoBf72uA+N +6rIVf1JBUL2p7HFHaGdUZC7KGQ+yv6ZHrE1+7202nuDvJdvGEEdFsQ== +-----END RSA PRIVATE KEY----- +", + samlServicePublicKeyEnc => "-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnfKBDG/K0TnGT7Xu8q1N +45sNWvIK91SqNg8nvN2uVeKoHADTcsus5Xn3id5+8Q9TuMFsW9kIEeXiaPKXQa9r +yfSNDhWDWloNkpGEeWif2BnHUu46Abu1UBWb0mH6VwcG1PR4qHruLis1odjQ1qnV +DNfSEASVIppEBYjDX203ypmURIzU6h53GRRRlf1BLWkbVn9ysmDeR57Xw5Rsx/+t +BlcnMrkv/40DSUkehQIl2JmlFrl2Caik+gU4pd20apA/pNLjBZF0OmGoS08AIR5N +Md0KFa6CwZUUSHJqH5GFy5Y2yl4lg8K0klAS9q7L7aXI+eFQZhkwidjpxXnHPyxI +GQIDAQAB +-----END PUBLIC KEY----- +", + samlServicePublicKeySig => "-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtR/wgDqWB4Maho5V6Tjc +L/NbNfjgIh7GcgkrB5RZcVT1GTejJlMjUQdgBKBuZXQN+7/29P6UcGq1kYalURq6 +S8SpeJ1ofp5rBEoD/TIkvU0JOcid65wp+fdzXGXsfiZvHraU74jSCgjP/wqfVGRy +BIQzB0SIxSpnrsigqNsE1E94toDMx4wovjHu/9ABAImREV7Sz83OeFF00/sghrjT +EJOD/gHf04JCn9MgNOqvSTysr9LXWg/oUKQDEYeTq9ux6pq/oqv1MxwONbSZPtN5 +yD41mi+hT8Rh+W8Je8rsiML4VMxzsb1l9303asw6suo5bLTISKNSbu1nt1NkpNxz +ywIDAQAB +-----END PUBLIC KEY----- +", + samlSPMetaDataXML => { + "sp.com" => { + samlSPMetaDataXML => + samlSPMetaDataXML( 'sp', 'HTTP-Redirect' ) + }, + }, + } + } + ); +} + +sub sp { + return LLNG::Manager::Test->new( { + ini => { + logLevel => $debug, + domain => 'sp.com', + portal => 'http://auth.sp.com', + authentication => 'SAML', + userDB => 'Same', + issuerDBSAMLActivation => 0, + restSessionServer => 1, + samlIDPMetaDataExportedAttributes => { + idp => { + mail => "0;mail;;", + uid => "1;uid", + cn => "0;cn" + } + }, + samlIDPMetaDataOptions => { + idp => { + samlIDPMetaDataOptionsEncryptionMode => 'none', + samlIDPMetaDataOptionsSSOBinding => 'redirect', + samlIDPMetaDataOptionsSLOBinding => 'redirect', + samlIDPMetaDataOptionsSignSSOMessage => 1, + samlIDPMetaDataOptionsSignSLOMessage => 1, + samlIDPMetaDataOptionsCheckSSOMessageSignature => 1, + samlIDPMetaDataOptionsCheckSLOMessageSignature => 1, + samlIDPMetaDataOptionsForceUTF8 => 1, + } + }, + samlIDPMetaDataExportedAttributes => { + idp => { + "uid" => "0;uid;;", + "cn" => "1;cn;;", + }, + }, + samlIDPMetaDataXML => { + idp => { + samlIDPMetaDataXML => + samlIDPMetaDataXML( 'idp', 'HTTP-Redirect' ) + } + }, + samlOrganizationDisplayName => "SP", + samlOrganizationName => "SP", + samlOrganizationURL => "http://www.sp.com", + samlServicePublicKeySig => "-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu4iToYAEmWQxgZDihGVz +MMql1elPn37domWcvXeU2E4yt2hh5jkQHiFjgodfOlNeRIw5QJVlUBwr+CQvbaKR +FXd7BrOhQIDC0TZPRVB0XHarUtsCuDekN4/2GKSzHsoToKUVPWq9thsuek3xkpsJ +GZNX7bglfEc9+QQpYTqN1rkdN1PVU0epNMokFFGho5pLRqLUV5+I/QXAL49jfTja +Sxsp4UndTI8/+mGSRSq+nrT2zyQRM/vkj5vR9ZVz67HO/+Wk3Mx6RAwkVcMdgMAq +Cq8odmbI0yCRZiTL9ybKWRKqWJoKJ0p5+Q2fPEBPupQZR09Jt/JPuLVSsGfCxi9N +qwIDAQAB +-----END PUBLIC KEY----- +", + samlServicePrivateKeyEnc => "-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAsRaod2RZ8hMFBl+VhsnhyPM8l/Fj1obnBxfQIaWuHFIFfXiG +e/CYHuZ5QJQLnZxHMJX6LL3Sh+Usog3p0jpijpcg0QgfBSEkfopKTgReYN8DiDIl +l0rV1XdTni7E85Nd1YyNy3ui/ZD+UShWwqu6jLVLR+QUm+/1LIKYb3OCBTvOlY7x +HoP6NSU1+Mr+YzGBUacdO2vnNxe/PQhxIeP1zO0njuqGHkwEpy8rUWRZbbDn31Tm +Kjqlhgtsz5HPhbRaYEExhyepKgBiNz+RyxtYXVhuG8OrWQDoS5gYHSjdw1CTJyix +eJwyoqA9RGYguG5nh9zndi3LWAh7Z0lx+tIz+wIDAQABAoIBAEkZrk8iiJKJ0WAx +IrsyKNbXuWKLTYgnxcRCyzKofrfID+YcU39j8JeI0fKbajQUZ7qhnlTLwtU//+2h +SqzyVu6/add/v7ZRWQw3L7cGzKK2THHzKVtLk/t7N3QroDdf1LMrQvkFP2HmcWS0 +/yN62hXtXHb/qpY4Nn+6JQyUpM5dkv8S/QjDl2NTdyWrXKzWp+4I3QLQ20f4zym+ +ir7RennziMc0HlQNcTjGAUbFULtdqEfSFWhNK7UjiRY+S0XV2xJIbGjnxUQH62fS +w1ZzYsF7sBtoSckvfL4WfGbylhOVnliU05RLU2c67PRjj1Gskoslq1Ow/3DHR7rI +BSBpV8ECgYEA1eHfcog7xQGDkW+cshJtFPFx+9MegB58gFW1rl0rn+tfbexvoSEA +7G7EOTyaU6OAI+8StiRT6AYTgEU7PMM9zDykdGIWj3h0OpHGA86xhEiiaaM2DDRv +/DEKRVlEdmRLLLY28pJVHOMYomia3mb2VKZGg2VfGtSfjg1GXD3I8OECgYEA0/X0 +U55KjZ1JQTPUgFc1WK1NxX9MaH+NcpDaolEUy3Qf3QTbfws+a9K3vwCn7EpQhrfs +I6RVUtwFdCyfl/jzBY9Gykkg03sMgW7Qw2SCCsSt05M+jDtBbNJ7esP6PAeKFvXZ +ZWhdeiAa4kM/P6gtvZXQ4tY4LkSbcd6b0SzzFFsCgYBjMsusFzuBd95JyfZnMNye +5gzzu0teKMWd0CLfqB7foQ81sH9lwCTpg8ZGtbDuMdrwz6ViDR9NceQBjhqXaAZ1 +f3rW79d+22Ms9wdcJLV4oSeSzzv2FSwLT8NvvqNeNc4YArshbnVDXKDEUrfhhueh +Ay2ZK58clpkaDVYg2hckgQKBgG3KuhtSI/YE4fwXN9yez7A2XNGPZem/IGqWo9lu +PGJCrXqT2IqPLW82gB083r6jo+CUhonTxqqb82tA7g4PUvqvQ5Dmnk1NMKYe255K +gp3HUO8GF2EWFIak5Hcr6oOLuDi6cjh3/euTk7ld8fYsTD0mzEOjiQhWW1p5X6bT +LLp/AoGAHvkxA1NM1HJ3myAREbwNXxRy/nhNt4mwMkZ6hPQsW/Eg/3r7j6MJOFrm +U8AJJjDGKe6nlXhhnMoQfJzAc0cYNgjktmJXW27fHGIwt/2QwYNFHPK3s7HTrfH6 +7T4XKT3yGeeeyC2soKJQPlGB+ETdIUnXa7eo9KVWtMTgISyx1Qk= +-----END RSA PRIVATE KEY----- +", + samlServicePrivateKeySig => "-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAu4iToYAEmWQxgZDihGVzMMql1elPn37domWcvXeU2E4yt2hh +5jkQHiFjgodfOlNeRIw5QJVlUBwr+CQvbaKRFXd7BrOhQIDC0TZPRVB0XHarUtsC +uDekN4/2GKSzHsoToKUVPWq9thsuek3xkpsJGZNX7bglfEc9+QQpYTqN1rkdN1PV +U0epNMokFFGho5pLRqLUV5+I/QXAL49jfTjaSxsp4UndTI8/+mGSRSq+nrT2zyQR +M/vkj5vR9ZVz67HO/+Wk3Mx6RAwkVcMdgMAqCq8odmbI0yCRZiTL9ybKWRKqWJoK +J0p5+Q2fPEBPupQZR09Jt/JPuLVSsGfCxi9NqwIDAQABAoIBABE0Cjb6g3F+23vD +SsRSeiqzrFrfOEqtXK+VGrfWzHS7V7Ozg6eW/H+HGJXUzUuQcklfg7EFA3JB41a0 +GxW3oA+UElkfCV/dcAG5NbRqGQKScEz9glZb5FikgDLqiPP+HabS/gvQSu71t2HI +3KxSRJdwCNTp26Z28pxxYUpmELTtxd9vlHjffit2Mnt2uc8hOtFHdNavfYwvYH7o +bmlckp7b/JVOy2Yy21O94ZWkE498jXyn71Gr+V1cnJ0RrmYbhQqIvFpFHj98Pf4O +if3c4YmBcZ4t7PUsZUYF3ooWt8k/mdigQC3D6p80OKe+wUTYKcCN0ZdFbiURv9pg +CsqLh+ECgYEA9vA+9QfzvXC7S5yXgTkuRiusPlNye/AiyA/0oGjmjFZ1YNsT7awH +6BjW6WE+rS4elKJu1GaefM/cDguH4ZmJc+eKgi4LDCqYw9rr9les3aneBc8demd3 +O/Ej1Pud1QxXArBNfBYo08vEqwST9P89clJC5090U6bGK2E0rTVu1w0CgYEAwmpG +9LbOFeGCPmwX7Avuk7tQQfRSV6q9TFZo+HxDfKYvxec846l1vBenY2rrgYhtolYJ +YS795LYgbSWRxGfgr1GuIbP5GsjHy6/1o6bS8M++GJ7KHArb0QLAYyQweqqb164A +NvHJkveueWnxzeOlD9j2fcjEnBHwTnqjG+17CZcCgYEAqMXawa4FsNxzpmIISpHC +RsNindZ60Kp3mzUMhPYtXI1a/C+/lxmU7dTMTgXgyIxU6lF6XkEk4TlPtWm8HTzK +7SS7Te4aLt6OOo5N57hUtct7q4y7IQXGQHm3e8HdRdeBQJ0u2Dhs/xSt/hTK6w/n +91Kx11Y+s02w88UkM53pe6ECgYAF/UYwVc1liSv9BlF6WSfBb1zam09KGh1405Sq +SxG9LlV8cFJE5TyWTdg/TNTyiaRvAt2JG+yAdkfrdOPXvCeE3yxRJ30+IP9evA4C +O6p19sBxe7rYQFFjUAVjSIMh1E22yEqDZtGB8JV0chob8K5uHY4CdAPylu7jTA3o +V1maAwKBgQCSGQ3yzsk4EGN2xd/JdgGDzhKyTZTQKMWYqQcsYxRAQ7Paj7u+Wkgv +dBeKcI0HwgpLy5ZohSd2erqieIsW0pEbJWCmos4IcO8tgNfEOa5WXYdyLbj5tFwt +ctu4/BJdijqfpMAtG8pv6k09gYjfASVytXmydGcs/0rVKYCRQA8Tow== +-----END RSA PRIVATE KEY----- +", + samlServicePublicKeyEnc => "-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsRaod2RZ8hMFBl+Vhsnh +yPM8l/Fj1obnBxfQIaWuHFIFfXiGe/CYHuZ5QJQLnZxHMJX6LL3Sh+Usog3p0jpi +jpcg0QgfBSEkfopKTgReYN8DiDIll0rV1XdTni7E85Nd1YyNy3ui/ZD+UShWwqu6 +jLVLR+QUm+/1LIKYb3OCBTvOlY7xHoP6NSU1+Mr+YzGBUacdO2vnNxe/PQhxIeP1 +zO0njuqGHkwEpy8rUWRZbbDn31TmKjqlhgtsz5HPhbRaYEExhyepKgBiNz+RyxtY +XVhuG8OrWQDoS5gYHSjdw1CTJyixeJwyoqA9RGYguG5nh9zndi3LWAh7Z0lx+tIz ++wIDAQAB +-----END PUBLIC KEY----- +", + samlSPSSODescriptorAuthnRequestsSigned => 1, + }, + } + ); +} From e40568a330026aff337768da3f3d55e79a331f96 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Fri, 31 Jan 2020 17:43:49 +0100 Subject: [PATCH 07/94] Manager: fix SSLVarIf syntax (#2082) --- .../lib/Lemonldap/NG/Manager/Attributes.pm | 5 ++++- .../lib/Lemonldap/NG/Manager/Build/Attributes.pm | 3 ++- .../lib/Lemonldap/NG/Portal/Auth/SSL.pm | 15 ++++++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm index 68f612518..7c86ff585 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm @@ -3648,7 +3648,10 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- }, 'SSLVarIf' => { 'default' => {}, - 'type' => 'keyTextContainer' + 'keyTest' => sub { + 1; + }, + 'type' => 'keyTextContainer' }, 'staticPrefix' => { 'type' => 'text' diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm index 0672ffd3f..9575bb0ce 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm @@ -358,7 +358,7 @@ sub attributes { msgFail => '__badUrl__', }, portalCustomCss => { - type => 'text', + type => 'text', documentation => 'Path to custom CSS file', }, portalStatus => { @@ -3147,6 +3147,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: }, SSLVarIf => { type => 'keyTextContainer', + keyTest => sub { 1 }, default => {} }, sslByAjax => { diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm index f2f9cc2b1..bf21bc0d1 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm @@ -32,12 +32,17 @@ sub init { sub extractFormInfo { my ( $self, $req ) = @_; my $field = $self->conf->{SSLVar}; - if ( $req->env->{SSL_CLIENT_I_DN} - and my $tmp = - $self->conf->{SSLVarIf}->{ $req->env->{SSL_CLIENT_I_DN} } ) - { - $field = $tmp; + if ( $req->env->{SSL_CLIENT_I_DN} ) { + $self->logger->debug( + 'Received SSL issuer ' . $req->env->{SSL_CLIENT_I_DN} ); + + if ( my $tmp = + $self->conf->{SSLVarIf}->{ $req->env->{SSL_CLIENT_I_DN} } ) + { + $field = $tmp; + } } + $self->logger->debug("Using SSL environment variable $field"); if ( $req->user( $req->env->{$field} ) ) { $self->userLogger->notice( "GoodSSL authentication for " . $req->user ); return PE_OK; From f4b11e9a0d6cdf0e79be5076a723e0067f95931e Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Fri, 31 Jan 2020 17:48:21 +0100 Subject: [PATCH 08/94] fix whitespace (#2082) --- lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm index bf21bc0d1..606111afd 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/SSL.pm @@ -34,7 +34,7 @@ sub extractFormInfo { my $field = $self->conf->{SSLVar}; if ( $req->env->{SSL_CLIENT_I_DN} ) { $self->logger->debug( - 'Received SSL issuer ' . $req->env->{SSL_CLIENT_I_DN} ); + 'Received SSL issuer ' . $req->env->{SSL_CLIENT_I_DN} ); if ( my $tmp = $self->conf->{SSLVarIf}->{ $req->env->{SSL_CLIENT_I_DN} } ) From 23b8756f2b3dd4286e1306963ad487c9c68afad2 Mon Sep 17 00:00:00 2001 From: Xavier Bachelot Date: Tue, 7 Jan 2020 14:51:55 +0100 Subject: [PATCH 09/94] Unbundle Time::Fake --- lemonldap-ng-handler/t/Time-Fake.pm | 235 ------------------------ lemonldap-ng-handler/t/test-psgi-lib.pm | 5 +- lemonldap-ng-portal/t/Time-Fake.pm | 235 ------------------------ lemonldap-ng-portal/t/test-lib.pm | 2 +- rpm/lemonldap-ng.spec | 1 + 5 files changed, 3 insertions(+), 475 deletions(-) delete mode 100644 lemonldap-ng-handler/t/Time-Fake.pm delete mode 100644 lemonldap-ng-portal/t/Time-Fake.pm diff --git a/lemonldap-ng-handler/t/Time-Fake.pm b/lemonldap-ng-handler/t/Time-Fake.pm deleted file mode 100644 index b37032bac..000000000 --- a/lemonldap-ng-handler/t/Time-Fake.pm +++ /dev/null @@ -1,235 +0,0 @@ -package Time::Fake; -use Carp; -use strict; -use vars '$VERSION'; -$VERSION = "0.11"; - -##################### - -my $OFFSET = 0; - -*CORE::GLOBAL::time = sub() { CORE::time() + $OFFSET }; - -*CORE::GLOBAL::localtime = sub(;$) { - @_ ? CORE::localtime($_[0]) - : CORE::localtime(CORE::time() + $OFFSET); -}; - -*CORE::GLOBAL::gmtime = sub(;$) { - @_ ? CORE::gmtime($_[0]) - : CORE::gmtime(CORE::time() + $OFFSET); -}; - -sub import { - my $pkg = shift; - $pkg->offset(shift); -} - -sub offset { - my $pkg = shift; - return $OFFSET if !@_; - - my $old_offset = $OFFSET; - $OFFSET = _to_offset(shift); - return $old_offset; -} - -sub reset { - shift->offset(0); -} - -my %mult = ( - s => 1, - m => 60, - h => 60*60, - d => 60*60*24, - M => 60*60*24*30, - y => 60*60*24*365, -); - -sub _to_offset { - my $t = shift || return 0; - - if ($t =~ m/^([+-]\d+)([smhdMy]?)$/) { - $t = $1 * $mult{ $2 || "s" }; - - } elsif ($t !~ m/\D/) { - $t = $t - CORE::time; - - } else { - croak "Invalid time offset: `$t'"; - } - - return $t; -} - -1; - -__END__ - -=head1 NAME - -Time::Fake - Simulate different times without changing your system clock - -=head1 SYNOPSIS - -Pretend we are running 1 day in the future: - - use Time::Fake '+1d'; - -Pretend we are running 1 year in the past: - - use Time::Fake '-1y'; - -Pretend the script started at epoch time 1234567: - - use Time::Fake 1234567; - -See what an existing script would do if run 20 years in the future: - - % perl -MTime::Fake="+20y" test.pl - -Run a section of code in a time warp: - - use Time::Fake; - - # do some setup - - Time::Fake->offset("+1y"); - run_tests(); # thinks it's a year ahead - - Time::Fake->reset; # back to the present - -=head1 DESCRIPTION - -Use this module to achieve the effect of changing your system clock, but -without actually changing your system clock. It overrides the Perl builtin -subs C