Commit c1212147 authored by Christophe Maudoux's avatar Christophe Maudoux

Backport all v2.1 improvements

parent 33a7a1b1
......@@ -193,6 +193,7 @@ t/05-rest-api.t
t/06-rest-api.t
t/07-utf8.t
t/10-save-unchanged-conf.t
t/11-save-changed-conf-with-confirmation.t
t/12-save-changed-conf.t
t/14-bad-changes-in-conf.t
t/15-combination.t
......@@ -206,6 +207,7 @@ t/99-pod.t
t/conf/lmConf-1.json
t/jsonfiles/01-base-tree.json
t/jsonfiles/02-base-tree-all-nodes-opened.json
t/jsonfiles/11-modified-with-confirmation.json
t/jsonfiles/12-modified.json
t/jsonfiles/14-bad.json
t/jsonfiles/15-combination.json
......
......@@ -56,8 +56,11 @@ sub addRoutes {
# New key and conf save
->addRoute(
confs =>
{ newRSAKey => 'newRSAKey', raw => 'newRawConf', '*' => 'newConf' },
confs => {
newRSAKey => 'newRSAKey',
raw => 'newRawConf',
'*' => 'newConf'
},
['POST']
)
......@@ -137,11 +140,12 @@ sub prx {
return $self->sendError( $req,
$response->code . " (" . $response->message . ")", 400 );
}
unless ( $response->header('Content-Type') =~
m#^(?:application/json|(?:application|text)/.*xml).*$# )
unless ( $response->header('Content-Type')
=~ m#^(?:application/json|(?:application|text)/.*xml).*$# )
{
return $self->sendError( $req,
'Content refused for security reason (neither XML or JSON)', 400 );
'Content refused for security reason (neither XML or JSON)',
400 );
}
return $self->sendJSONresponse( $req, { content => $response->content } );
}
......@@ -228,11 +232,18 @@ sub newConf {
# "message" fields: note that words enclosed by "__" (__word__) will be
# translated
$res->{details}->{'__errors__'} = $parser->{errors}
if ( @{ $parser->{errors} } );
unless ( @{ $parser->{errors} } ) {
$res->{details}->{'__needConfirmation__'}
= $parser->{needConfirmation}
if ( @{ $parser->{needConfirmation} } && !$req->params('force') );
$res->{message} = $parser->{message};
foreach my $t (qw(errors warnings changes)) {
foreach my $t (qw(warnings changes)) {
$res->{details}->{ '__' . $t . '__' } = $parser->$t
if ( @{ $parser->$t } );
}
}
if ( $res->{result} ) {
if ( $self->{demoMode} ) {
$res->{message} = '__demoModeOn__';
......@@ -240,7 +251,9 @@ sub newConf {
else {
my %args;
$args{force} = 1 if ( $req->params('force') );
my $s = $self->confAcc->saveConf( $parser->newConf, %args );
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->userId($req) . " has stored conf $s" );
......@@ -259,7 +272,8 @@ sub newConf {
$res->{result} = 0;
if ( $s == CONFIG_WAS_CHANGED ) {
$res->{needConfirm} = 1;
$res->{message} .= '__needConfirmation__';
$res->{message} .= '__needConfirmation__'
unless @{ $parser->{needConfirmation} };
}
else {
$res->{message} = $Lemonldap::NG::Common::Conf::msg;
......@@ -325,8 +339,8 @@ sub applyConf {
$self->api->checkConf();
# Get apply section values
my %reloadUrls =
%{ $self->confAcc->getLocalConf( APPLYSECTION, undef, 0 ) };
my %reloadUrls
= %{ $self->confAcc->getLocalConf( APPLYSECTION, undef, 0 ) };
if ( !%reloadUrls && $newConf->{reloadUrls} ) {
%reloadUrls = %{ $newConf->{reloadUrls} };
}
......@@ -342,10 +356,10 @@ sub applyConf {
my $targetUrl = $url->scheme . "://" . $host;
$targetUrl .= ":" . $url->port if defined( $url->port );
$targetUrl .= $url->full_path;
$r =
HTTP::Request->new( 'GET', $targetUrl,
$r = HTTP::Request->new( 'GET', $targetUrl,
HTTP::Headers->new( Host => $url->host ) );
if ( defined $url->userinfo && $url->userinfo =~ /^([^:]+):(.*)$/ )
if ( defined $url->userinfo
&& $url->userinfo =~ /^([^:]+):(.*)$/ )
{
$r->authorization_basic( $1, $2 );
}
......@@ -353,8 +367,10 @@ sub applyConf {
my $response = $self->ua->request($r);
if ( $response->code != 200 ) {
$status->{$host} =
"Error " . $response->code . " (" . $response->message . ")";
$status->{$host}
= "Error "
. $response->code . " ("
. $response->message . ")";
$self->logger->error( "Apply configuration for $host: error "
. $response->code . " ("
. $response->message
......@@ -373,13 +389,13 @@ sub diff {
my ( $self, $req, @path ) = @_;
return $self->sendError( $req, 'to many arguments in path info', 400 )
if (@path);
my @cfgNum =
( scalar( $req->param('conf1') ), scalar( $req->param('conf2') ) );
my @cfgNum
= ( scalar( $req->param('conf1') ), scalar( $req->param('conf2') ) );
my @conf;
$self->logger->debug(" Loading confs");
# Load the 2 configurations
for ( my $i = 0 ; $i < 2 ; $i++ ) {
for ( my $i = 0; $i < 2; $i++ ) {
if ( %{ $self->currentConf }
and $cfgNum[$i] == $self->currentConf->{cfgNum} )
{
......@@ -390,7 +406,7 @@ sub diff {
{ cfgNum => $cfgNum[$i], raw => 1, noCache => 1 } );
return $self->sendError(
$req,
"Configuration $cfgNum[$i] not available $Lemonldap::NG::Common::Conf::msg",
"Configuration $cfgNum[$i] not available $Lemonldap::NG::Common::Conf::msg",
400
) unless ( $conf[$i] );
}
......@@ -398,8 +414,7 @@ sub diff {
require Lemonldap::NG::Manager::Conf::Diff;
return $self->sendJSONresponse(
$req,
[
$self->Lemonldap::NG::Manager::Conf::Diff::diff(
[ $self->Lemonldap::NG::Manager::Conf::Diff::diff(
$conf[0], $conf[1]
)
]
......
......@@ -260,9 +260,9 @@ sub tests {
},
# Warn if session timeout is lower than 10 minutes
timeoutActivity => sub {
sessionTimeout => sub {
return 1 unless ( defined $conf->{timeout} );
return ( 1, "Session timeout should be higher than ten minutes" )
return ( -1, "Session timeout should be higher than ten minutes" )
unless ( $conf->{timeout} > 600
|| $conf->{timeout} == 0 );
......@@ -271,7 +271,7 @@ sub tests {
},
# Error if session Activity Timeout is equal or lower than one minute
timeoutActivity => sub {
sessionTimeoutActivity => sub {
return 1 unless ( defined $conf->{timeoutActivity} );
return ( 0,
"Session activity timeout must be higher or equal than one minute"
......@@ -609,13 +609,16 @@ sub tests {
# Warn if Mailrest plugin is enabled without Token or Captcha
checkMailResetSecurity => sub {
return 1 unless ( $conf->{portalDisplayResetPassword} );
return ( 1,
'"passwordMailReset" plugin is enabled without CSRF Token or Captcha required !!!'
) unless ( $conf->{requireToken} or $conf->{captcha_mail_enabled} );
return ( -1,
'"passwordMailReset" plugin is enabled without CSRF Token neither Captcha required !!!'
)
unless ( $conf->{requireToken}
or $conf->{captcha_mail_enabled} );
# Return
return 1;
},
};
}
......
......@@ -144,10 +144,15 @@ llapp.controller 'TreeCtrl', [
title: ''
message: ''
items: []
$scope.confirmNeeded = true if data.message == '__needConfirmation__'
$scope.confirmNeeded = true if data.needConfirm
$scope.message.message = data.message if data.message
if data.details
for m of data.details when m != '__changes__'
if m == '__needConfirmation__'
$scope.message.items.unshift
message: m
items: data.details[m]
else
$scope.message.items.push
message: m
items: data.details[m]
......
......@@ -170,7 +170,7 @@ This file contains:
message: '',
items: []
};
if (data.message === '__needConfirmation__') {
if (data.needConfirm) {
$scope.confirmNeeded = true;
}
if (data.message) {
......@@ -179,6 +179,12 @@ This file contains:
if (data.details) {
for (m in data.details) {
if (m !== '__changes__') {
if (m === '__needConfirmation__') {
$scope.message.items.unshift({
message: m,
items: data.details[m]
});
} else {
$scope.message.items.push({
message: m,
items: data.details[m]
......@@ -186,6 +192,7 @@ This file contains:
}
}
}
}
$scope.waiting = false;
if (data.result === 1) {
$location.path('/confs/');
......
......@@ -236,6 +236,7 @@
"enabled":"مفعلة",
"enterPassword":"أدخل كلمة المرور (اختياري)",
"error":"خطأ",
"errors":"ERRORS",
"exportedAttr":"SOAP/REST السمات المصدرة",
"exportedHeaders":"الهيدر المصدرة",
"exportedVars":"المتغيرات المصدرة",
......
......@@ -236,6 +236,7 @@
"enabled":"Aktiviert",
"enterPassword":"Enter password (optional)",
"error":"Error",
"errors":"ERRORS",
"exportedAttr":"SOAP/REST exported attributes",
"exportedHeaders":"Exported headers",
"exportedVars":"Exported Variables",
......
......@@ -236,6 +236,7 @@
"enabled":"Enabled",
"enterPassword":"Enter password (optional)",
"error":"Error",
"errors":"ERRORS",
"exportedAttr":"SOAP/REST exported attributes",
"exportedHeaders":"Exported headers",
"exportedVars":"Exported Variables",
......
......@@ -236,6 +236,7 @@
"enabled":"Activé",
"enterPassword":"Entrer le mot de passe (optionnel)",
"error":"Erreur",
"errors":"ERREURS",
"exportedAttr":"Attributs exportés par le portail (SOAP/REST)",
"exportedHeaders":"En-têtes exportés",
"exportedVars":"Attributs à exporter",
......
......@@ -236,6 +236,7 @@
"enabled":"Abilitato",
"enterPassword":"Inserisci password (opzionale)",
"error":"Errore",
"errors":"ERRORS",
"exportedAttr":"Attributi di SOAP/REST esportati",
"exportedHeaders":"Intestazioni esportate",
"exportedVars":"Variabili esportate",
......
......@@ -236,6 +236,7 @@
"enabled":"Đã bật",
"enterPassword":"Nhập mật khẩu (tùy chọn)",
"error":"Lỗi",
"errors":"ERRORS",
"exportedAttr":"Biến SOAP/REST đã được xuất",
"exportedHeaders":"Tiêu đề đã được xuất",
"exportedVars":"Biến đã được xuất",
......
......@@ -236,6 +236,7 @@
"enabled":"开启",
"enterPassword":"输入密码(可选)",
"error":"错误",
"errors":"ERRORS",
"exportedAttr":"SOAP/REST exported attributes",
"exportedHeaders":"Exported headers",
"exportedVars":"Exported Variables",
......
# Verify that a modified configuration can be saved and that all changes are
# detected
use Test::More;
use strict;
use JSON;
require 't/test-lib.pm';
my $struct = 't/jsonfiles/11-modified-with-confirmation.json';
my $confFiles = [ 't/conf/lmConf-1.json', 't/conf/lmConf-2.json' ];
sub body {
return IO::File->new( $struct, 'r' );
}
# Delete lmConf-2.json if exists
eval { unlink $confFiles->[1]; };
mkdir 't/sessions';
my ( $res, $resBody );
ok( $res = &client->_post( '/confs/', 'cfgNum=1', &body, 'application/json' ),
"Request succeed"
);
ok( $res->[0] == 200, "Result code is 200" );
ok( $resBody = from_json( $res->[2]->[0] ),
"Result body contains JSON text" );
ok( $resBody->{result} == 0, "JSON response contains \"result:0\"" )
or print STDERR Dumper($resBody);
ok( $resBody->{needConfirm} == 1, "JSON response contains \"needConfirm:1\"" )
or print STDERR Dumper($resBody);
ok( @{ $resBody->{details}->{__warnings__} } == 3,
'JSON response contains 3 warnings'
) or print STDERR Dumper($resBody);
foreach my $i (0 .. 2) {
ok( $resBody->{details}->{__warnings__}->[$i]->{message}
=~ /\b(unprotected|cross-domain-authentication|retries)\b/,
"Warning with 'unprotect', 'CDA' or 'retries' found"
) or print STDERR Dumper($resBody);
}
count(4);
ok( @{ $resBody->{details}->{__needConfirmation__} } == 1,
'JSON response contains 1 needConfirmation'
) or print STDERR Dumper($resBody);
ok( $resBody->{details}->{__needConfirmation__}->[0]->{message}
=~ /\bplugin is enabled without CSRF Token neither Captcha required\b/,
"Warning with confirmation needed found"
) or print STDERR Dumper($resBody);
ok( @{ $resBody->{details}->{__changes__} } == 22,
'JSON response contains 24 changes'
) or print STDERR Dumper($resBody);
#print STDERR Dumper($resBody);
ok( $res = &client->_post( '/confs/', 'cfgNum=1&force=1', &body, 'application/json' ),
"Request succeed"
);
ok( -f $confFiles->[1], 'File is created' );
count(5);
my @changes = @{&changes};
my @cmsg = @{ $resBody->{details}->{__changes__} };
my $bug;
while ( my $c = shift @{ $resBody->{details}->{__changes__} } ) {
my $cmp1 = @changes;
my $cmp2 = @cmsg;
my @d1 = grep { $_->{key} eq $c->{key} } @changes;
my @d2 = grep { $_->{key} eq $c->{key} } @cmsg;
@changes = grep { $_->{key} ne $c->{key} } @changes;
@cmsg = grep { $_->{key} ne $c->{key} } @cmsg;
if ( $c->{key} eq 'applicationList' ) {
pass qq("$c->{key}" found);
}
else {
ok( ( $cmp1 - @changes ) == ( $cmp2 - @cmsg ), qq("$c->{key}" found) )
or print STDERR 'Expect: '
. ( $cmp1 - @changes )
. ', got: '
. ( $cmp2 - @cmsg )
. "\nExpect: "
. Dumper( \@d1 ) . "Got: "
. Dumper( \@d2 );
}
count(1);
}
ok( !@changes, 'All changes detected' ) or $bug = 1;
if ($bug) {
print STDERR 'Expected not found: '
. Dumper( \@changes )
. 'Changes announced and not found: '
. Dumper( \@cmsg );
}
#print STDERR Dumper(\@changes,\@cmsg);
count(6);
# TODO: check result of this
ok( $res = &client->jsonResponse('/diff/1/2'), 'Diff called' );
my ( @c1, @c2 );
ok( ( @c1 = sort keys %{ $res->[0] } ), 'diff() detects changes in conf 1' );
ok( ( @c2 = sort keys %{ $res->[1] } ), 'diff() detects changes in conf 2' );
ok( @c1 == 12, '11 keys changed in conf 1' )
or print STDERR "Expect: 12 keys, get: " . join( ', ', @c1 ) . "\n";
ok( @c2 == 16, '14 keys changed or created in conf 2' )
or print STDERR "Expect: 16 keys, get: " . join( ',', @c2 ) . "\n";
count(5);
unlink $confFiles->[1];
#eval { rmdir 't/sessions'; };
done_testing( count() );
# Remove sessions directory
`rm -rf t/sessions`;
sub changes {
return [
{ 'key' => 'portal',
'new' => 'http://auth2.example.com/',
'old' => 'http://auth.example.com/'
},
{ 'new' => 0,
'old' => 1,
'key' => 'portalDisplayLogout'
},
{ 'key' =>
'applicationList, Sample applications, Application Test 1, uri',
'old' => 'http://test1.example.com/',
'new' => 'http://testex.example.com/'
},
{ 'new' => 'Application Test 3',
'key' => 'applicationList, Sample applications'
},
{ 'new' => 'Changes in cat(s)/app(s)',
'key' => 'applicationList',
},
{ 'key' => 'applicationList',
'old' => 'Documentation',
'new' => 'Administration',
},
{ 'key' => 'applicationList',
'old' => 'Administration',
'new' => 'Sample applications',
},
{ 'key' => 'applicationList',
'old' => 'Sample applications',
'new' => 'Documentation',
},
{ 'key' => 'userDB',
'new' => 'LDAP',
'old' => 'Demo'
},
{ 'key' => 'passwordDB',
'new' => 'LDAP',
'old' => 'Demo'
},
{ 'key' => 'openIdSPList',
'new' => '1;bad.com'
},
{ 'new' => 'Uid',
'key' => 'exportedVars'
},
{ 'key' =>
'locationRules, test1.example.com, (?#Logout comment)^/logout',
'new' => 'logout_sso',
'old' => undef
},
{ 'old' => '^/logout',
'key' => 'locationRules, test1.example.com'
},
{ 'key' => 'locationRules, test3.example.com, ^/logout',
'new' => 'logout_sso',
'old' => undef
},
{ 'key' => 'locationRules, test3.example.com, default',
'old' => undef,
'new' => 'accept'
},
{ 'key' => 'locationRules',
'new' => 'test3.example.com'
},
{ 'key' => 'exportedHeaders, test3.example.com, Auth-User',
'old' => undef,
'new' => '$uid'
},
{ 'new' => 'test3.example.com',
'key' => 'exportedHeaders'
},
{ 'key' => 'locationRules, test.ex.com, default',
'old' => undef,
'new' => 'deny'
},
{ 'key' => 'locationRules',
'new' => 'test.ex.com'
},
{ 'key' => 'virtualHosts',
'new' => 'test3.example.com',
'old' => 'test2.example.com'
},
{ 'key' => 'virtualHosts',
'old' => 'test2.example.com'
},
{
'new' => 1,
'key' => 'portalDisplayResetPassword',
'old' => 0
},
{
'new' => 0,
'key' => 'captcha_mail_enabled',
'old' => '1'
}
];
}
......@@ -26,20 +26,24 @@ 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__}
and @{ $resBody->{details}->{__warnings__} } == 2,
ok( @{ $resBody->{details}->{__warnings__} } == 2,
'JSON response contains 2 warnings'
) or print STDERR Dumper($resBody);
ok( $resBody->{details}->{__warnings__}->[0]->{message}
=~ /\b(unprotected|cross-domain-authentication)\b/,
"Warning with 'unprotect' or 'CDA' found"
) or print STDERR Dumper($resBody);
ok( $resBody->{details}->{__warnings__}->[1]->{message}
foreach my $i (0 .. 1) {
ok( $resBody->{details}->{__warnings__}->[$i]->{message}
=~ /\b(unprotected|cross-domain-authentication)\b/,
"Warning with 'unprotect' or 'CDA' found"
"Warning with 'unprotect', 'CDA' or 'retries' found"
) or print STDERR Dumper($resBody);
}
ok( @{ $resBody->{details}->{__changes__} } == 20,
'JSON response contains 24 changes'
) or print STDERR Dumper($resBody);
#print STDERR Dumper($resBody);
ok( -f $confFiles->[1], 'File is created' );
count(3);
count(4);
my @changes = @{&changes};
my @cmsg = @{ $resBody->{details}->{__changes__} };
my $bug;
......
......@@ -12,6 +12,7 @@ sub body {
}
unlink 't/conf/lmConf-2.json';
mkdir 't/sessions';
my ( $res, $resBody );
ok( $res = &client->_post( '/confs/', 'cfgNum=1', &body, 'application/json' ),
......@@ -38,3 +39,5 @@ count(9);
done_testing( count() );
unlink 't/conf/lmConf-2.json';
`rm -rf t/sessions`;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment