Merge branch 'v2.0'

This commit is contained in:
Christophe Maudoux 2021-05-03 23:23:50 +02:00
commit 779f79bace
22 changed files with 88 additions and 108 deletions

View File

@ -122,7 +122,9 @@ sub saveConf {
# If configuration was modified, return an error
if ( not $args{force} ) {
return CONFIG_WAS_CHANGED if ( $conf->{cfgNum} != $last );
return CONFIG_WAS_CHANGED
if ( $conf->{cfgNum} ne $last
|| $args{cfgDate} && $args{cfgDate} ne $args{currentCfgDate} );
return DATABASE_LOCKED if ( $self->isLocked() or not $self->lock() );
}
$conf->{cfgNum} = $last + 1 unless ( $args{cfgNumFixed} );

View File

@ -65,9 +65,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)
- nohistory : do not increment configuration number (requires -force 1)
- sep <char> : separator of hierarchical values (by default: /)
- iniFile <file> : path to an alternative lemonldap-ng.ini file
- iniFile <file> : path to an alternate lemonldap-ng.ini file
See Lemonldap::NG::Manager::Cli(3) for more
};
@ -179,10 +178,6 @@ Allows you to force overwriting an existing configuration (default: 0)
Choose a particular configuration number (default: latest)
=item -nohistory
Allows you to keep current configuration number
=item -sep
Allows you to define hierarchical separator

View File

@ -29,7 +29,6 @@ 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 nohistory => ( is => 'rw', isa => 'Bool', default => 0 );
has logger => ( is => 'ro', lazy => 1, builder => sub { $_[0]->mgr->logger } );
has userLogger =>
( is => 'ro', lazy => 1, builder => sub { $_[0]->mgr->userLogger } );
@ -356,7 +355,7 @@ sub rollback {
or die $Lemonldap::NG::Common::Conf::msg;
$conf->{cfgNum} = $lastCfg;
$conf->{cfgAuthor} = scalar( getpwuid $< ) . ' (command-line-interface)';
$conf->{cfgAuthor} = scalar( getpwuid $< ) . '(command-line-interface)';
chomp $conf->{cfgAuthor};
$conf->{cfgAuthorIP} = '127.0.0.1';
$conf->{cfgDate} = time;
@ -433,7 +432,6 @@ sub _save {
print STDERR "$msg\n";
}
}
my $saveParams = { force => $self->force };
if ( $self->force and $self->cfgNum ) {
$self->logger->debug( "CLI: cfgNum forced with " . $self->cfgNum );
@ -441,15 +439,6 @@ sub _save {
$saveParams->{cfgNum} = $self->cfgNum;
$saveParams->{cfgNumFixed} = 1;
}
if ( $self->force and $self->nohistory ) {
my $lastCfg = $self->mgr->confAcc->lastCfg;
$self->logger->debug(
"CLI: No history required. cfgNum forced with " . $lastCfg );
print STDERR "No history required. cfgNum forced with ", $lastCfg;
$saveParams->{cfgNum} = $lastCfg;
$saveParams->{cfgNumFixed} = 1;
}
$new->{cfgAuthor} = scalar( getpwuid $< ) . '(command-line-interface)';
chomp $new->{cfgAuthor};
$new->{cfgAuthorIP} = '127.0.0.1';

View File

@ -123,7 +123,7 @@ sub newRSAKey {
my $keys = {
'private' => $rsa->get_private_key_string(),
'public' => $rsa->get_public_key_x509_string(),
'hash' => md5_base64($rsa->get_public_key_string()),
'hash' => md5_base64( $rsa->get_public_key_string() ),
};
if ( $query->{password} ) {
my $pem = Convert::PEM->new(
@ -345,26 +345,25 @@ sub newConf {
# Body must be json
my $new = $req->jsonBodyToObj;
unless ( defined($new) ) {
return $self->sendError( $req, undef, 400 );
}
return $self->sendError( $req, undef, 400 ) unless ( defined $new );
# Verify that cfgNum has been asked
unless ( defined $req->params('cfgNum') ) {
return $self->sendError( $req, "Missing configuration number", 400 );
}
# Verify that cfgNum has been sent
return $self->sendError( $req, "Missing configuration number", 400 )
unless ( defined $req->params('cfgNum') );
# # Verify that cfgDate has been sent
# return $self->sendError( $req, "Missing configuration date", 400 )
# unless ( defined $req->params('cfgDate') );
# Set current conf to cfgNum
unless ( defined $self->getConfByNum( $req->params('cfgNum') ) ) {
return $self->sendError(
$req,
"Configuration "
. $req->params('cfgNum')
. " not available "
. $Lemonldap::NG::Common::Conf::msg,
400
);
}
return $self->sendError(
$req,
"Configuration "
. $req->params('cfgNum')
. " not available "
. $Lemonldap::NG::Common::Conf::msg,
400
) unless ( defined $self->getConfByNum( $req->params('cfgNum') ) );
# Parse new conf
require Lemonldap::NG::Manager::Conf::Parser;
@ -372,13 +371,20 @@ sub newConf {
{ tree => $new, refConf => $self->currentConf, req => $req } );
# If ref conf isn't last conf, consider conf changed
my $cfgNum = $self->confAcc->lastCfg;
unless ( defined $cfgNum ) {
$req->error($Lemonldap::NG::Common::Conf::msg);
}
my $currentCfgNum = $self->confAcc->lastCfg;
$req->error($Lemonldap::NG::Common::Conf::msg)
unless ( defined $currentCfgNum );
return $self->sendError( $req, undef, 400 ) if ( $req->error );
if ( $cfgNum ne $req->params('cfgNum') ) { $parser->confChanged(1); }
my $currentConf =
$self->confAcc->getConf(
{ CfgNum => $currentCfgNum, raw => 1, noCache => 1 } );
my $currentCfgDate = $currentConf->{cfgDate};
$self->logger->debug(
"Current CfgNum/cfgDate: $currentCfgNum/$currentCfgDate");
$parser->confChanged(1)
if ( $currentCfgNum ne $req->params('cfgNum')
|| $req->params('cfgDate')
&& $req->params('cfgDate') ne $currentCfgDate );
my $res = { result => $parser->check( $self->p ) };
@ -396,39 +402,38 @@ sub newConf {
}
}
if ( $res->{result} ) {
if ( $self->p->{demoMode} ) {
$res->{message} = '__demoModeOn__';
my %args;
$args{force} = 1 if ( $req->params('force') );
if ( $req->params('cfgDate') ) {
$args{cfgDate} = $req->params('cfgDate');
$args{currentCfgDate} = $currentCfgDate;
}
my $s = CONFIG_WAS_CHANGED;
$s = $self->confAcc->saveConf( $parser->newConf, %args )
unless ( @{ $parser->{needConfirmation} } && !$args{force} );
if ( $s > 0 ) {
$self->userLogger->notice(
'User ' . $self->p->userId($req) . " has stored conf $s" );
$res->{result} = 1;
$res->{cfgNum} = $s;
if ( my $status = $self->applyConf( $parser->newConf ) ) {
push @{ $res->{details}->{__applyResult__} },
{ message => "$_: $status->{$_}" }
foreach ( keys %$status );
}
}
else {
my %args;
$args{force} = 1 if ( $req->params('force') );
my $s = CONFIG_WAS_CHANGED;
$s = $self->confAcc->saveConf( $parser->newConf, %args )
unless ( @{ $parser->{needConfirmation} } && !$args{force} );
if ( $s > 0 ) {
$self->userLogger->notice(
'User ' . $self->p->userId($req) . " has stored conf $s" );
$res->{result} = 1;
$res->{cfgNum} = $s;
if ( my $status = $self->applyConf( $parser->newConf ) ) {
push @{ $res->{details}->{__applyResult__} },
{ message => "$_: $status->{$_}" }
foreach ( keys %$status );
}
$self->userLogger->notice(
'Saving attempt rejected, asking for confirmation to '
. $self->p->userId($req) );
$res->{result} = 0;
if ( $s == CONFIG_WAS_CHANGED ) {
$res->{needConfirm} = 1;
$res->{message} .= '__needConfirmation__'
unless @{ $parser->{needConfirmation} };
}
else {
$self->userLogger->notice(
'Saving attempt rejected, asking for confirmation to '
. $self->p->userId($req) );
$res->{result} = 0;
if ( $s == CONFIG_WAS_CHANGED ) {
$res->{needConfirm} = 1;
$res->{message} .= '__needConfirmation__'
unless @{ $parser->{needConfirmation} };
}
else {
$res->{message} = $Lemonldap::NG::Common::Conf::msg;
}
$res->{message} = $Lemonldap::NG::Common::Conf::msg;
}
}
}

View File

@ -189,7 +189,7 @@ llapp.controller 'TreeCtrl', [
id: "cfgLog"
title: "cfgLog"
data: if $scope.result then $scope.result else ''
$http.post("#{window.confPrefix}?cfgNum=#{$scope.currentCfg.cfgNum}#{if $scope.forceSave then "&force=1" else ''}", $scope.data).then (response) ->
$http.post("#{window.confPrefix}?cfgNum=#{$scope.currentCfg.cfgNum}&cfgDate=#{$scope.currentCfg.cfgDate}#{if $scope.forceSave then "&force=1" else ''}", $scope.data).then (response) ->
$scope.data.pop()
_checkSaveResponse response.data
,(response) ->

View File

@ -225,7 +225,7 @@ This file contains:
title: "cfgLog",
data: $scope.result ? $scope.result : ''
});
return $http.post(window.confPrefix + "?cfgNum=" + $scope.currentCfg.cfgNum + ($scope.forceSave ? "&force=1" : ''), $scope.data).then(function(response) {
return $http.post(window.confPrefix + "?cfgNum=" + $scope.currentCfg.cfgNum + "&cfgDate=" + $scope.currentCfg.cfgDate + ($scope.forceSave ? "&force=1" : ''), $scope.data).then(function(response) {
$scope.data.pop();
return _checkSaveResponse(response.data);
}, function(response) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -77,7 +77,7 @@
"authChain":"سلسلة إثبات الهوية",
"authChoice":"اختيار إثبات الهوية",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"FindUser plugin parameter",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"الوحدات المسموح بها",
"authChoiceParam":"معايير URL",
"authOnly":"إثبات الهوية فقط",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Delete TOTP key",
"deleteU2FKey":"Delete U2F key",
"demoExportedVars":"المتغيرات المصدرة",
"demoModeOn":"هذا المدير يعمل في طريقة العرض",
"demoParams":"إثبات المعايير",
"description":"التفاصيل",
"dest":"Recipient",

View File

@ -77,7 +77,7 @@
"authChain":"Authentication chain",
"authChoice":"Authentication choice",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"FindUser plugin parameter",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"Allowed modules",
"authChoiceParam":"URL parameter",
"authOnly":"Authentication only",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Delete TOTP key",
"deleteU2FKey":"Delete U2F key",
"demoExportedVars":"Exported variables",
"demoModeOn":"This manager runs in demo mode",
"demoParams":"Demonstration parameters",
"description":"Beschreibung",
"dest":"Recipient",

View File

@ -77,7 +77,7 @@
"authChain":"Authentication chain",
"authChoice":"Authentication choice",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"FindUser plugin parameter",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"Allowed modules",
"authChoiceParam":"URL parameter",
"authOnly":"Authentication only",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Delete TOTP key",
"deleteU2FKey":"Delete U2F key",
"demoExportedVars":"Exported variables",
"demoModeOn":"This manager runs in demo mode",
"demoParams":"Demonstration parameters",
"description":"Description",
"dest":"Recipient",

View File

@ -77,7 +77,7 @@
"authChain":"Cadena de autentificación",
"authChoice":"Opción de autentificación",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"FindUser plugin parameter",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"Módulos permitidos",
"authChoiceParam":"Parámetro URL",
"authOnly":"Sólo autentificación",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Borrar clave TOTP",
"deleteU2FKey":"Borrar clave U2F",
"demoExportedVars":"Variables exportadas",
"demoModeOn":"Este gestor se ejecuta en modo de pruebas",
"demoParams":"Parámetros de prueba",
"description":"Descripción",
"dest":"Recipient",

View File

@ -77,7 +77,7 @@
"authChain":"Chaîne d'authentification",
"authChoice":"Choix d'authentification",
"authChoiceAuthBasic":"Choix à utiliser pour l'authentification par mot de passe",
"authChoiceFindUser":"Paramètre de recherche de compte",
"authChoiceFindUser":"Choix à utiliser pour la recherche de compte",
"authChoiceModules":"Modules autorisés",
"authChoiceParam":"Paramètre de l'URL",
"authOnly":"Authentification seulement",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Supprimer la clef TOTP",
"deleteU2FKey":"Supprimer la clef U2F",
"demoExportedVars":"Variables exportées",
"demoModeOn":"Ce manager fonctionne en mode Demo",
"demoParams":"Paramètres démonstration",
"description":"Description",
"dest":"Destinataire",

View File

@ -77,7 +77,7 @@
"authChain":"Catena di autenticazione",
"authChoice":"Scelta di autenticazione",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"FindUser plugin parameter",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"Moduli consentiti",
"authChoiceParam":"Parametri URL",
"authOnly":"Solo autenticazione",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Elimina la chiave TOTP",
"deleteU2FKey":"Elimina la chiave U2F",
"demoExportedVars":"Variabili esportate",
"demoModeOn":"Questo gestore viene eseguito in modalità demo",
"demoParams":"Parametri di dimostrazione",
"description":"Descrizione",
"dest":"Recipient",

View File

@ -77,7 +77,7 @@
"authChain":"Łańcuch uwierzytelnienia",
"authChoice":"Wybór uwierzytelnienia",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"Parametr wtyczki FindUser",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"Dozwolone moduły",
"authChoiceParam":"Parametr adresu URL",
"authOnly":"Tylko uwierzytelnianie",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Usuń klucz TOTP",
"deleteU2FKey":"Usuń klucz U2F",
"demoExportedVars":"Wyeksportowane zmienne",
"demoModeOn":"Ten menedżer działa w trybie demonstracyjnym",
"demoParams":"Parametry demonstracyjne",
"description":"Opis",
"dest":"Odbiorca",

View File

@ -77,7 +77,7 @@
"authChain":"Doğrulama zinciri",
"authChoice":"Kimlik doğrulama tercihi",
"authChoiceAuthBasic":"Parola doğrulaması için kullanılan seçim",
"authChoiceFindUser":"FindUser eklenti parametresi",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"İzin verilen modüller",
"authChoiceParam":"URL parametresi",
"authOnly":"Yalnızca kimlik doğrulama",
@ -313,7 +313,6 @@
"deleteTOTPKey":"TOTP anahtarını sil",
"deleteU2FKey":"U2F anahtarını sil",
"demoExportedVars":"Dışa aktarılan değişkenler",
"demoModeOn":"Bu yönetici demo modunda çalışıyor",
"demoParams":"Gösterim parametreleri",
"description":"Açıklama",
"dest":"Alıcı",

View File

@ -77,7 +77,7 @@
"authChain":"Chuỗi xác thực",
"authChoice":"Lựa chọn xác thực",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"FindUser plugin parameter",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"Các mô-đun được phép",
"authChoiceParam":"Tham số URL",
"authOnly":"Chỉ xác thực",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Delete TOTP key",
"deleteU2FKey":"Delete U2F key",
"demoExportedVars":"Xuất khẩu biến",
"demoModeOn":"Trình quản lý này chạy ở chế độ demo",
"demoParams":"Tham số trình diễn",
"description":"Mô tả",
"dest":"Recipient",

View File

@ -77,7 +77,7 @@
"authChain":"认证chain",
"authChoice":"认证方式选择",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"FindUser plugin parameter",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"允许的模块",
"authChoiceParam":"URL 参数",
"authOnly":"Authentication only",
@ -313,7 +313,6 @@
"deleteTOTPKey":"Delete TOTP key",
"deleteU2FKey":"Delete U2F key",
"demoExportedVars":"Exported variables",
"demoModeOn":"This manager runs in demo mode",
"demoParams":"Demonstration parameters",
"description":"Description",
"dest":"Recipient",

View File

@ -77,7 +77,7 @@
"authChain":"驗證鏈",
"authChoice":"驗證選擇",
"authChoiceAuthBasic":"Choice used for password authentication",
"authChoiceFindUser":"FindUser plugin parameter",
"authChoiceFindUser":"Choice used for searching user account",
"authChoiceModules":"已允許的模組",
"authChoiceParam":"URL 參數",
"authOnly":"僅驗證",
@ -313,7 +313,6 @@
"deleteTOTPKey":"刪除 TOTP 金鑰",
"deleteU2FKey":"刪除 U2F 金鑰",
"demoExportedVars":"已匯出的變數",
"demoModeOn":"此管理程式以示範模式運作",
"demoParams":"示範參數",
"description":"描述",
"dest":"接收者",

View File

@ -4,7 +4,7 @@ use JSON;
use strict;
require 't/test-lib.pm';
my $tests = 18;
my $tests = 17;
use_ok('Lemonldap::NG::Common::Cli');
use_ok('Lemonldap::NG::Manager::Cli');
@ -77,14 +77,6 @@ combined_like(
'"Force cfgNum" OK'
);
# Test 'set' command with nohistory
@cmd = qw(-yes 1 -force 1 -nohistory 1 set cookieName test);
combined_like(
sub { llclient->run(@cmd) },
qr#cfgNum forced with 6#s,
'"Force cfgNum" OK'
);
# Test 'info' command with force
@cmd = qw(info);
combined_like(

View File

@ -57,6 +57,10 @@ div.actions a {
margin-top: 10px;
}
div.actions button {
margin-top: 10px;
}
.buttons {
text-align: center;
margin: 10px 0 0 0;

View File

@ -1 +1 @@
html,body{height:100%;background:radial-gradient(circle at 50% 0,#fff 0,#ddd 100%) no-repeat scroll 0 0 #ddd}#wrap{min-height:100%;height:auto;margin:0 auto -80px;padding:20px 0 80px}#footer{height:80px;background-color:#fff;background-color:rgba(255,255,255,0.9);text-align:center;padding-top:10px;overflow:hidden}#header img{background-color:#fff;background-color:rgba(255,255,255,0.8);margin-bottom:20px}.card,.navbar-light{background-color:#fff;background-color:rgba(255,255,255,0.9);background-image:none}.login,.password{text-align:center;padding:20px}div.form{margin:0 auto;max-width:330px}div.actions{margin:10px 0 0 0}div.actions a{margin-top:10px}.buttons{text-align:center;margin:10px 0 0 0;cursor:pointer}.btn{white-space:normal}.btn span.fa{padding-right:8px}li.ui-state-active{background-color:#fafafa;background-color:rgba(250,250,250,0.9)}#appslist,#password,#loginHistory,#logout,#oidcConsents{margin-top:20px}div.category{margin:10px 0;cursor:grab}div.application{margin:5px 0;overflow:hidden}div.application a,div.application a:hover{text-decoration:none}p.notifCheck label{margin-left:5px;margin-top:3px;display:inline-block}img.langicon{cursor:pointer}button.idploop{max-width:300px}button.idploop img{max-height:30px}div.oidc_consent_message>ul{text-align:left;list-style:circle}@media(min-width:768px){div.application{height:80px}div.application h4.appname{margin:0}#wrap{margin:0 auto -60px}#footer{height:60px}}.hiddenFrame{border:0;display:hidden;margin:0}.noborder{border:0}.max{width:100%}.link{cursor:pointer}.nodecor:hover,.nodecor:active,.nodecor:focus{text-decoration:none}.fa.icon-blue{color:blue}.progress-bar-animated{width:100%}input.key{font-family:'password';width:100px}@font-face{font-family:'password';src:url(/static/common/fonts/password.ttf)}.info.table caption{color:black;text-align:center;caption-side:bottom}div.input-group>p.form-control{height:auto}div.input-group>p.form-control>label{display:revert;user-select:none;cursor:pointer}
html,body{height:100%;background:radial-gradient(circle at 50% 0,#fff 0,#ddd 100%) no-repeat scroll 0 0 #ddd}#wrap{min-height:100%;height:auto;margin:0 auto -80px;padding:20px 0 80px}#footer{height:80px;background-color:#fff;background-color:rgba(255,255,255,0.9);text-align:center;padding-top:10px;overflow:hidden}#header img{background-color:#fff;background-color:rgba(255,255,255,0.8);margin-bottom:20px}.card,.navbar-light{background-color:#fff;background-color:rgba(255,255,255,0.9);background-image:none}.login,.password{text-align:center;padding:20px}div.form{margin:0 auto;max-width:330px}div.actions{margin:10px 0 0 0}div.actions a{margin-top:10px}div.actions button{margin-top:10px}.buttons{text-align:center;margin:10px 0 0 0;cursor:pointer}.btn{white-space:normal}.btn span.fa{padding-right:8px}li.ui-state-active{background-color:#fafafa;background-color:rgba(250,250,250,0.9)}#appslist,#password,#loginHistory,#logout,#oidcConsents{margin-top:20px}div.category{margin:10px 0;cursor:grab}div.application{margin:5px 0;overflow:hidden}div.application a,div.application a:hover{text-decoration:none}p.notifCheck label{margin-left:5px;margin-top:3px;display:inline-block}img.langicon{cursor:pointer}button.idploop{max-width:300px}button.idploop img{max-height:30px}div.oidc_consent_message>ul{text-align:left;list-style:circle}@media(min-width:768px){div.application{height:80px}div.application h4.appname{margin:0}#wrap{margin:0 auto -60px}#footer{height:60px}}.hiddenFrame{border:0;display:hidden;margin:0}.noborder{border:0}.max{width:100%}.link{cursor:pointer}.nodecor:hover,.nodecor:active,.nodecor:focus{text-decoration:none}.fa.icon-blue{color:blue}.progress-bar-animated{width:100%}input.key{font-family:'password';width:100px}@font-face{font-family:'password';src:url(/static/common/fonts/password.ttf)}.info.table caption{color:black;text-align:center;caption-side:bottom}div.input-group>p.form-control{height:auto}div.input-group>p.form-control>label{display:revert;user-select:none;cursor:pointer}