Merge branch 'v2.0'

This commit is contained in:
Christophe Maudoux 2020-09-02 18:55:23 +02:00
commit 937bdd4e8b
11 changed files with 115 additions and 19 deletions

View File

@ -257,6 +257,16 @@ To set a parameter, for example domain:
/usr/share/lemonldap-ng/bin/lemonldap-ng-cli set domain example.org
To delete a parameter, for example portalSkinBackground:
::
/usr/share/lemonldap-ng/bin/lemonldap-ng-cli del portalSkinBackground
.. tip::
Use addKey and delKey actions to manage values of hash configuration parameters
You can use accessors (options) to change the behavior:
- -sep: separator of hierarchical values (by default: /).

View File

@ -168,7 +168,7 @@ Execute an unit test :
# and execute the unit test:
prove -v t/67-CheckUser.t
Launch tests with LDAP backend, for example with OpenLDAP LTB package:
Launch tests with LDAP backend, for example with OpenLDAP LTB package (https://ltb-project.org/documentation):
::

View File

@ -21,7 +21,7 @@ backups and a rollback plan ready!
-----
- | Bad default value to display OIDC Consents tab has been fixed.
| The default value is ``$_oidcConsents``
| The default value is ``$_oidcConsents && $_oidcConsents =~ /\w+/``
- Some user log messages have been modified, check :doc:`logs documentation <logs>`
(see also `#2244 <https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues/2244>`__)
- SAML SOAP calls are now using ``text/xml`` instead of ``application/xml`` as the MIME Content Type, as required by `the SOAP standard <https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383526>`__
@ -36,6 +36,8 @@ backups and a rollback plan ready!
- This release fixes several issues when using ``SameSite=None``. The new
default value of the SameSite configuration parameter will set SameSite to
``Lax`` unless you are using SAML, which requires ``None``
- Incremental lock times values can now be set by using Manager.
It must a list of comma separated values. Default values are ``5, 15, 60, 300, 600``
2.0.8
-----

View File

@ -22,7 +22,7 @@ for ( my $i = 0 ; $i < @ARGV ; $i++ ) {
$action ||= "help";
if ( $action =~ /^(?:[gs]et|(?:add|del)Key|save|restore|rollback)$/ ) {
if ( $action =~ /^(?:[gs]et|del|(?:add|del)Key|save|restore|rollback)$/ ) {
eval { require Lemonldap::NG::Manager::Cli; };
die "Manager libraries not available, aborting ($@)" if ($@);
Lemonldap::NG::Manager::Cli->run(@ARGV);
@ -45,6 +45,7 @@ Available actions:
- update-cache : force configuration cache to be updated
- get <keys> : get values of parameters
- set <key> <value> : set parameter(s) value(s)
- del <keys> : delete parameters
- addKey <key> <subkey> <value> : add or set a subkey in a parameter
- delKey <key> <subkey> : delete subkey of a parameter
- save : export configuration to STDOUT
@ -58,6 +59,8 @@ Options:
- safe <0|1> : fail in case the requested configuration is invalid
- force <0|1> : allow overwrite of existing config number
- cfgNum <num> : set new configuration number (requires -force 1)
- sep <char> : separator of hierarchical values (by default: /)
- iniFile <file> : path to an alternate lemonldap-ng.ini file
See Lemonldap::NG::Manager::Cli(3) for more
};

View File

@ -4,6 +4,7 @@ use strict;
use Crypt::URandom;
use Mouse;
use Data::Dumper;
use JSON;
use Lemonldap::NG::Common::Conf::ReConstants;
our $VERSION = '2.1.0';
@ -83,6 +84,43 @@ sub set {
return $self->_save($new);
}
sub del {
my ( $self, @keys ) = @_;
die 'del requires at least one key' unless (@keys);
my $oldValues = {};
foreach my $key (@keys) {
my $value = $self->_getKey($key);
if ( ref $value eq 'HASH' ) {
print STDERR "$key seems to be a hash, delete refused\n";
next;
}
unless ( defined $value ) {
print STDERR "$key does not exists, skip it\n";
next;
}
$oldValues->{$key} = $value;
}
return unless keys %$oldValues;
unless ( $self->yes ) {
print "Proposed changes:\n";
printf "%-25s | %-25s\n", 'Key', 'Old value';
foreach ( keys %$oldValues ) {
printf "%-25s | %-25s\n", $_, $oldValues->{$_};
}
print "Confirm (N/y)? ";
my $c = <STDIN>;
unless ( $c =~ /^y(?:es)?$/ ) {
die "Aborting";
}
}
require Clone;
my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf );
foreach ( keys %$oldValues ) {
delete $new->{$_};
}
return $self->_save($new);
}
sub addKey {
my $self = shift;
unless ( @_ % 3 == 0 ) {
@ -348,10 +386,22 @@ sub _save {
printf STDERR "Modifications rejected: %s:\n", $parser->{message}
if $parser->{message};
}
# Open "en" lang file to get default messages
my $langFile = $self->mgr->templateDir . "/languages/en.json";
$langFile =~ s/templates/static/;
my $langMessages;
if ( open my $json, "<", $langFile ) {
local $/ = undef;
$langMessages = JSON::from_json(<$json>);
}
# Display result
foreach (qw(errors warnings status)) {
if ( $parser->{$_} and @{ $parser->{$_} } ) {
my $s = Dumper( $parser->{$_} );
$s =~ s/\$VAR1\s*=\s*//;
$s =~ s/__(\w+)__/$langMessages->{$1}/ if ( defined $langMessages );
printf STDERR "%-8s: %s", ucfirst($_), $s;
}
}
@ -383,8 +433,11 @@ sub run {
}
$self->cfgNum( $self->lastCfg ) unless ( $self->cfgNum );
my $action = shift;
unless ( $action =~ /^(?:get|set|addKey|delKey|save|restore|rollback)$/ ) {
die "Unknown action $action. Only get, set, addKey or delKey allowed";
unless (
$action =~ /^(?:get|set|del|addKey|delKey|save|restore|rollback)$/ )
{
die
"Unknown action $action. Only get, set, del, addKey, delKey, save, restore, rollback allowed";
}
$self->$action(@_);

View File

@ -226,7 +226,7 @@ sub tests {
eval { tied(%h)->delete; };
return ( -1, "Unable to delete session ($@)" ) if ($@);
return ( -1,
'All sessions may be lost and you must restart all your Apache servers'
'All sessions may be lost and you must restart all your web servers'
) if ( $gc and $conf->{globalStorage} ne $gc );
return 1;
},

View File

@ -132,7 +132,7 @@
<h3 id="mtitle" class="modal-title" trspan="{{elem('message').title}}" />
<TMPL_IF NAME="INSTANCE_NAME"><h4><TMPL_VAR NAME="INSTANCE_NAME"></h4></TMPL_IF>
</div>
<div ng-if="elem('message').message" id="mbody" class="modal-body">
<div ng-if="elem('message').items[0] || elem('message').message" id="mbody" class="modal-body">
<div class="modal-p">{{translateP(elem('message').message)}}</div>
<ul class="main-modal-ul" ng-model="elem('message').items">
<li ng-repeat="item in elem('message').items" ng-include="'messageitem.html'"/>

View File

@ -40,7 +40,7 @@ has unrestrictedUsersRule => ( is => 'rw', default => sub { 0 } );
sub init {
my ($self) = @_;
$self->addAuthRoute( switchcontext => 'run', ['POST'] )
$self->addAuthRoute( switchcontext => 'run', ['POST'] )
->addAuthRoute( switchcontext => 'display', ['GET'] );
# Parse ContextSwitching rules
@ -193,7 +193,7 @@ sub run {
$self->userLogger->notice(
"ContextSwitching: Update \"$realId\" session with \"$spoofId\" session data"
);
$req->mustRedirect(1);
return $self->p->do( $req, [ sub { $statut } ] );
}

View File

@ -2,8 +2,11 @@ package Lemonldap::NG::Portal::Plugins::Impersonation;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants
qw( PE_OK PE_BADCREDENTIALS PE_IMPERSONATION_SERVICE_NOT_ALLOWED PE_MALFORMEDUSER );
use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK PE_BADCREDENTIALS
PE_IMPERSONATION_SERVICE_NOT_ALLOWED
PE_MALFORMEDUSER
);
our $VERSION = '2.1.0';
@ -77,7 +80,7 @@ sub run {
return $req->authResult
if $req->authResult >
PE_OK; # Skip Impersonation if error during Auth process
PE_OK; # Skip Impersonation if an error occurs during Auth process
my $statut = PE_OK;
my $unUser = 0;
@ -86,7 +89,7 @@ sub run {
$req->{user} ||= $req->{sessionInfo}->{_impUser}; # If 2FA is enabled
my $spoofId = $req->param('spoofId') # Impersonation required
|| $req->{sessionInfo}->{_impSpoofId} # If 2FA is enabled
|| $req->{user}; # NO Impersonation required
|| $req->{user}; # Impersonation not required
$self->logger->debug("No impersonation required")
if ( $spoofId eq $req->{user} );

View File

@ -7,7 +7,7 @@ require 't/test-lib.pm';
use lib 't/lib';
my $res;
my $maintests = 24;
my $maintests = 36;
SKIP: {
skip( 'LLNGTESTLDAP is not set', $maintests ) unless ( $ENV{LLNGTESTLDAP} );
@ -28,6 +28,13 @@ SKIP: {
managerPassword => 'lemonldapng',
ldapAllowResetExpiredPassword => 1,
ldapPpolicyControl => 1,
passwordPolicyMinSize => 4,
passwordPolicyMinLower => 1,
passwordPolicyMinUpper => 1,
passwordPolicyMinDigit => 1,
passwordPolicyMinSpeChar => 1,
passwordPolicySpecialChar => '@',
portalDisplayPasswordPolicy => 1
}
}
);
@ -67,10 +74,28 @@ SKIP: {
my ( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'oldpassword', 'newpassword',
'confirmpassword' );
ok( $res->[2]->[0] =~ m%<span trspan="passwordPolicyMinSize">%,
' passwordPolicyMinSize' )
or print STDERR Dumper( $res->[2]->[0], 'passwordPolicyMinSize' );
ok( $res->[2]->[0] =~ m%<span trspan="passwordPolicyMinLower">%,
' passwordPolicyMinLower' )
or print STDERR Dumper( $res->[2]->[0], 'passwordPolicyMinLower' );
ok( $res->[2]->[0] =~ m%<span trspan="passwordPolicyMinUpper">%,
' passwordPolicyMinUpper' )
or print STDERR Dumper( $res->[2]->[0], 'passwordPolicyMinUpper' );
ok( $res->[2]->[0] =~ m%<span trspan="passwordPolicyMinDigit">%,
' passwordPolicyMinDigit' )
or print STDERR Dumper( $res->[2]->[0], 'passwordPolicyMinDigit' );
ok( $res->[2]->[0] =~ m%<span trspan="passwordPolicyMinSpeChar">%,
' passwordPolicyMinSpeChar' )
or print STDERR Dumper( $res->[2]->[0], 'passwordPolicyMinSpeChar' );
ok( $res->[2]->[0] =~ m%<span trspan="passwordPolicySpecialChar">%,
' passwordPolicySpecialChar' )
or print STDERR Dumper( $res->[2]->[0], 'passwordPolicySpecialChar' );
ok( $query =~ /user=$user/, "User is $user" )
or explain( $query, "user=$user" );
$query =~ s/(oldpassword)=/$1=$user/g;
$query =~ s/((?:confirm|new)password)=/$1=newp/g;
$query =~ s/((?:confirm|new)password)=/$1=Newp1@/g;
ok(
$res = $client->_post(
'/', IO::String->new($query),
@ -82,7 +107,7 @@ SKIP: {
$match = 'trmsg="' . PE_PASSWORD_OK . '"';
ok( $res->[2]->[0] =~ /$match/, 'Password is changed' );
$postString = "user=$user&password=newp";
$postString = "user=$user&password=Newp1@";
ok(
$res = $client->_post(
'/', IO::String->new($postString),
@ -163,7 +188,7 @@ SKIP: {
);
my $id = expectCookie($res);
$query =
'oldpassword=passwordnottooshort&newpassword=test&confirmpassword=test';
'oldpassword=passwordnottooshort&newpassword=Te1@&confirmpassword=Te1@';
ok(
$res = $client->_post(
'/',
@ -189,7 +214,7 @@ SKIP: {
);
$id = expectCookie($res);
$query =
'oldpassword=passwordnottooshort&newpassword=testmore&confirmpassword=testmore';
'oldpassword=passwordnottooshort&newpassword=Testmore1@&confirmpassword=Testmore1@';
ok(
$res = $client->_post(
'/',

View File

@ -136,7 +136,7 @@ SKIP: {
expectOK($res);
my $id = expectCookie($res);
my @refs = ( $res->[2]->[0] =~
/<input type="hidden" name="reference[\dx]+" value="(\w+?)">/gs );
m#<input type="hidden" name="reference[\dx]+" value="(\w+?)"/>#gs );
ok( @refs == 2, 'Two notification references found' )
or print STDERR Dumper( $res->[2]->[0] );
ok( $refs[0] eq 'testref2', '1st reference found is "testref2"' )