Commit fb8ec238 authored by Christophe Maudoux's avatar Christophe Maudoux

Merge branch 'v2.0'

parents 7e9aaea6 6dee2f2d
......@@ -86,7 +86,7 @@
"authentication" : "Demo",
"cfgAuthor" : "The LemonLDAP::NG team",
"cfgNum" : 1,
"cfgVersion" : "2.0.2",
"cfgVersion" : "2.0.1",
"cookieName" : "lemonldap",
"demoExportedVars" : {
"cn" : "cn",
......
......@@ -121,9 +121,9 @@ sub defaultValues {
'macros' => {},
'mailCharset' => 'utf-8',
'mailFrom' => 'noreply@example.com',
'mailPwdRstUrl' => 'http://auth.example.com/resetpwd',
'mailSessionKey' => 'mail',
'mailTimeout' => 0,
'mailUrl' => 'http://auth.example.com/resetpwd',
'managerDn' => '',
'managerPassword' => '',
'max2FDevices' => 10,
......
......@@ -16,10 +16,8 @@ BEGIN { use_ok('Lemonldap::NG::Common::Conf') }
my $h;
ok(
$h = new Lemonldap::NG::Common::Conf(
{
type => 'File',
ok( $h = new Lemonldap::NG::Common::Conf(
{ type => 'File',
dirName => "t/",
}
),
......@@ -39,25 +37,27 @@ my @test = (
{ cfgNum => 1, test => 'éà' }
);
for ( my $i = 0 ; $i < @test ; $i++ ) {
for ( my $i = 0; $i < @test; $i++ ) {
ok( $h->store( $test[$i] ) == 1, "Test $i is stored" )
or print STDERR "$Lemonldap::NG::Common::Conf::msg $!";
or print STDERR "$Lemonldap::NG::Common::Conf::msg $!";
$count++;
if ( -x '/usr/bin/file' ) {
eval {
open F, 'file t/lmConf-1.json |';
$_ = join( '', <F> );
close F;
ok( /(ascii|utf-?8)/si, "File is $1 encoded" )
or print STDERR "Result: $_\n";
## Debian Buster 'file' command returns JSON DATA
ok( /(ascii|utf-?8|json\sdata)/si, "File is $1 encoded" )
or print STDERR "Result: $_\n";
$count++;
};
}
my $cfg;
ok( $cfg = $h->load(1), "Test $i can be read" )
or print STDERR $Lemonldap::NG::Common::Conf::msg;
or print STDERR $Lemonldap::NG::Common::Conf::msg;
ok( $cfg->{test} eq $test[$i]->{test}, "Test $i is restored" )
or print STDERR "Expect $cfg->{test} eq $test[$i]->{test}\n";
or print STDERR "Expect $cfg->{test} eq $test[$i]->{test}\n";
$count += 2;
}
......
......@@ -243,14 +243,6 @@ sub sfa {
$self->logger->debug(
"Removing sessions unless a $_ device is registered");
}
#else {
# (
# return $self->sendError(
# $req, "Bad or Missing " . $_ . "Check parameter", 400
# )
# );
#}
}
my $total = ( keys %$res );
......
......@@ -1558,19 +1558,10 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
},
'type' => 'keyTextContainer'
},
'mailBody' => {
'type' => 'longtext'
},
'mailCharset' => {
'default' => 'utf-8',
'type' => 'text'
},
'mailConfirmBody' => {
'type' => 'longtext'
},
'mailConfirmSubject' => {
'type' => 'text'
},
'mailFrom' => {
'default' => 'noreply@example.com',
'type' => 'text'
......@@ -1582,6 +1573,22 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'default' => 0,
'type' => 'bool'
},
'mailPwdRstBody' => {
'type' => 'longtext'
},
'mailPwdRstConfirmBody' => {
'type' => 'longtext'
},
'mailPwdRstConfirmSubject' => {
'type' => 'text'
},
'mailPwdRstSubject' => {
'type' => 'text'
},
'mailPwdRstUrl' => {
'default' => 'http://auth.example.com/resetpwd',
'type' => 'url'
},
'mailReplyTo' => {
'type' => 'text'
},
......@@ -1589,17 +1596,10 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'default' => 'mail',
'type' => 'text'
},
'mailSubject' => {
'type' => 'text'
},
'mailTimeout' => {
'default' => 0,
'type' => 'int'
},
'mailUrl' => {
'default' => 'http://auth.example.com/resetpwd',
'type' => 'url'
},
'maintenance' => {
'default' => 0,
'type' => 'bool'
......
......@@ -10,7 +10,6 @@ our $VERSION = '2.0.2';
use strict;
use Regexp::Common qw/URI/;
my $perlExpr = sub {
my ( $val, $conf ) = @_;
my $s = '';
......@@ -29,15 +28,15 @@ sub types {
# Simple text types
text => {
test => sub { 1 },
test => sub {1},
msgFail => '__malformedValue__',
},
password => {
test => sub { 1 },
test => sub {1},
msgFail => '__malformedValue__',
},
longtext => {
test => sub { 1 }
test => sub {1}
},
url => {
form => 'text',
......@@ -57,7 +56,7 @@ sub types {
pcre => {
form => 'text',
test => sub {
eval { qr/$_[0]/ };
eval {qr/$_[0]/};
return $@ ? ( 0, "__badRegexp__: $@" ) : (1);
},
},
......@@ -66,11 +65,11 @@ sub types {
test => sub {
my ( $val, $conf ) = @_;
return 1
if ( defined $conf->{macros}->{$val}
if ( defined $conf->{macros}->{$val}
or $val eq '_timezone' );
foreach ( keys %$conf ) {
return 1
if ( $_ =~ /exportedvars$/i
if ( $_ =~ /exportedvars$/i
and defined $conf->{$_}->{$val} );
}
return ( 1, "__unknownAttrOrMacro__: $val" );
......@@ -102,27 +101,27 @@ sub types {
},
subContainer => {
keyTest => qr/\w/,
test => sub { 1 },
test => sub {1},
},
select => {
test => sub {
my $test = grep ( { $_ eq $_[0] }
map ( { $_->{k} } @{ $_[2]->{select} } ) );
return $test
? 1
: ( 1, "Invalid value '$_[0]' for this select" );
? 1
: ( 1, "Invalid value '$_[0]' for this select" );
},
},
# Files type (long text)
file => {
test => sub { 1 }
test => sub {1}
},
RSAPublicKey => {
test => sub {
return (
$_[0] =~
/^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+PUBLIC\s+KEY\s*\-+)?[\r\n]*)?$/s
$_[0]
=~ /^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+PUBLIC\s+KEY\s*\-+)?[\r\n]*)?$/s
? (1)
: ( 1, '__badPemEncoding__' )
);
......@@ -131,8 +130,8 @@ sub types {
'RSAPublicKeyOrCertificate' => {
'test' => sub {
return (
$_[0] =~
/^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+)?[\r\n]*)?$/s
$_[0]
=~ /^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+)?[\r\n]*)?$/s
? (1)
: ( 1, '__badPemEncoding__' )
);
......@@ -141,8 +140,8 @@ sub types {
RSAPrivateKey => {
test => sub {
return (
$_[0] =~
/^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?(?:Proc-Type:.*\r?\nDEK-Info:.*\r?\n[\r\n]*)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:RSA\s+)PRIVATE\s+KEY\s*\-+)?[\r\n]*)?$/s
$_[0]
=~ /^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?(?:Proc-Type:.*\r?\nDEK-Info:.*\r?\n[\r\n]*)?[a-zA-Z0-9\/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:RSA\s+)PRIVATE\s+KEY\s*\-+)?[\r\n]*)?$/s
? (1)
: ( 1, '__badPemEncoding__' )
);
......@@ -150,13 +149,13 @@ sub types {
},
authParamsText => {
test => sub { 1 }
test => sub {1}
},
blackWhiteList => {
test => sub { 1 }
test => sub {1}
},
catAndAppList => {
test => sub { 1 }
test => sub {1}
},
keyText => {
keyTest => qr/^[a-zA-Z0-9_]+$/,
......@@ -164,52 +163,52 @@ sub types {
msgFail => '__badValue__',
},
menuApp => {
test => sub { 1 }
test => sub {1}
},
menuCat => {
test => sub { 1 }
test => sub {1}
},
oidcOPMetaDataNode => {
test => sub { 1 }
test => sub {1}
},
oidcRPMetaDataNode => {
test => sub { 1 }
test => sub {1}
},
oidcmetadatajson => {
test => sub { 1 }
test => sub {1}
},
oidcmetadatajwks => {
test => sub { 1 }
test => sub {1}
},
portalskin => {
test => sub { 1 }
test => sub {1}
},
portalskinbackground => {
test => sub { 1 }
test => sub {1}
},
post => {
test => sub { 1 }
test => sub {1}
},
rule => {
test => sub { 1 }
test => sub {1}
},
samlAssertion => {
test => sub { 1 }
test => sub {1}
},
samlAttribute => {
test => sub { 1 }
test => sub {1}
},
samlIDPMetaDataNode => {
test => sub { 1 }
test => sub {1}
},
samlSPMetaDataNode => {
test => sub { 1 }
test => sub {1}
},
samlService => {
test => sub { 1 }
test => sub {1}
},
array => {
test => sub { 1 }
test => sub {1}
},
};
}
......@@ -221,7 +220,7 @@ sub attributes {
checkTime => {
type => 'int',
documentation =>
'Timeout to check new configuration in local cache',
'Timeout to check new configuration in local cache',
default => 600,
flags => 'hp',
},
......@@ -229,7 +228,7 @@ sub attributes {
type => 'array',
documentation => 'Alterable session keys by user itself',
default =>
[ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ],
[ '_appsListOrder', '_oidcConnectedRP', '_oidcConsents' ],
},
configStorage => {
type => 'text',
......@@ -252,12 +251,14 @@ sub attributes {
documentation => 'Enable Cross Domain Authentication',
},
cfgAuthor => {
type => 'text',
documentation => 'Name of the author of the current configuration',
type => 'text',
documentation =>
'Name of the author of the current configuration',
},
cfgAuthorIP => {
type => 'text',
documentation => 'Uploader IP address of the current configuration',
type => 'text',
documentation =>
'Uploader IP address of the current configuration',
},
cfgDate => {
type => 'int',
......@@ -279,7 +280,7 @@ sub attributes {
confirmFormMethod => {
type => "select",
select =>
[ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
[ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
default => 'post',
documentation => 'HTTP method for confirm page form',
},
......@@ -300,7 +301,7 @@ sub attributes {
infoFormMethod => {
type => "select",
select =>
[ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
[ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
default => 'get',
documentation => 'HTTP method for info page form',
},
......@@ -315,10 +316,11 @@ sub attributes {
documentation => 'Use javascript for redirections',
},
logoutServices => {
type => 'keyTextContainer',
help => 'logoutforward.html',
default => {},
documentation => 'Send logout trough GET request to these services',
type => 'keyTextContainer',
help => 'logoutforward.html',
default => {},
documentation =>
'Send logout trough GET request to these services',
},
maintenance => {
default => 0,
......@@ -357,12 +359,12 @@ sub attributes {
type => 'text',
default => '_user',
documentation =>
'Session parameter to display connected user in portal',
'Session parameter to display connected user in portal',
},
redirectFormMethod => {
type => "select",
select =>
[ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
[ { k => 'get', v => 'GET' }, { k => 'post', v => 'POST' }, ],
default => 'get',
documentation => 'HTTP method for redirect page form',
},
......@@ -373,11 +375,11 @@ sub attributes {
flags => 'm',
},
reloadUrls => {
type => 'keyTextContainer',
help => 'configlocation.html#configuration_reload',
keyTest => qr/^$Regexp::Common::URI::RFC2396::host(?::\d+)?$/,
test => $url,
msgFail => '__badUrl__',
type => 'keyTextContainer',
help => 'configlocation.html#configuration_reload',
keyTest => qr/^$Regexp::Common::URI::RFC2396::host(?::\d+)?$/,
test => $url,
msgFail => '__badUrl__',
documentation => 'URL to call on reload',
},
portalMainLogo => {
......@@ -420,7 +422,7 @@ sub attributes {
type => 'bool',
default => 0,
documentation =>
'Avoid asking confirmation when an Issuer asks to renew auth',
'Avoid asking confirmation when an Issuer asks to renew auth',
},
handlerInternalCache => {
type => 'int',
......@@ -468,9 +470,9 @@ sub attributes {
# Manager or PSGI protected apps
protection => {
type => 'text',
test => qr/^(?:none|authenticate|manager|)$/,
msgFail => '__authorizedValues__: none authenticate manager',
type => 'text',
test => qr/^(?:none|authenticate|manager|)$/,
msgFail => '__authorizedValues__: none authenticate manager',
documentation => 'Manager protection method',
flags => 'hm',
},
......@@ -486,7 +488,8 @@ sub attributes {
keyTest => qr/\w/,
help => 'portalmenu.html#categories_and_applications',
default => {
default => { catname => 'Default category', type => "category" }
default =>
{ catname => 'Default category', type => "category" }
},
documentation => 'Applications list',
},
......@@ -499,7 +502,7 @@ sub attributes {
type => 'bool',
default => 0,
documentation =>
'Show error if mail is not found in password reset process',
'Show error if mail is not found in password reset process',
},
portalOpenLinkInNewWindow => {
type => 'bool',
......@@ -522,26 +525,22 @@ sub attributes {
documentation => 'Background image of portal skin',
select => [
{ k => "", v => 'None' },
{
k => "1280px-Anse_Source_d'Argent_2-La_Digue.jpg",
{ k => "1280px-Anse_Source_d'Argent_2-La_Digue.jpg",
v => 'Anse'
},
{
k =>
"1280px-Autumn-clear-water-waterfall-landscape_-_Virginia_-_ForestWander.jpg",
{ k =>
"1280px-Autumn-clear-water-waterfall-landscape_-_Virginia_-_ForestWander.jpg",
v => 'Waterfall'
},
{ k => "1280px-BrockenSnowedTrees.jpg", v => 'Snowed Trees' },
{
k => "1280px-Cedar_Breaks_National_Monument_partially.jpg",
{ k =>
"1280px-Cedar_Breaks_National_Monument_partially.jpg",
v => 'National Monument'
},
{
k => "1280px-Parry_Peak_from_Winter_Park.jpg",
{ k => "1280px-Parry_Peak_from_Winter_Park.jpg",
v => 'Winter'
},
{
k => "Aletschgletscher_mit_Pinus_cembra1.jpg",
{ k => "Aletschgletscher_mit_Pinus_cembra1.jpg",
v => 'Pinus'
},
],
......@@ -588,13 +587,13 @@ sub attributes {
help => 'forcereauthn.html',
type => 'bool',
documentation =>
'Enable force to authenticate when displaying portal',
'Enable force to authenticate when displaying portal',
},
portalForceAuthnInterval => {
default => 5,
type => 'int',
documentation =>
'Maximum interval in seconds since last authentication to force reauthentication',
'Maximum interval in seconds since last authentication to force reauthentication',
},
bruteForceProtection => {
default => 0,
......@@ -606,24 +605,24 @@ sub attributes {
default => 30,
type => 'int',
documentation =>
'Brute force attack protection -> Tempo before try again',
'Brute force attack protection -> Tempo before try again',
},
bruteForceProtectionMaxAge => {
default => 300,
type => 'int',
documentation =>
'Brute force attack protection -> Max age between last and first allowed failed login',
'Brute force attack protection -> Max age between last and first allowed failed login',
},
bruteForceProtectionMaxFailed => {
default => 3,
type => 'int',
documentation =>
'Brute force attack protection -> Max allowed failed login',
'Brute force attack protection -> Max allowed failed login',
},
grantSessionRules => {
type => 'grantContainer',
keyTest => $perlExpr,
test => sub { 1 },
test => sub {1},
documentation => 'Rules to grant sessions',
},
hiddenAttributes => {
......@@ -644,7 +643,7 @@ sub attributes {
type => 'text',
default => "'self'",
documentation =>
'Form action destination for Content-Security-Policy',
'Form action destination for Content-Security-Policy',
},
cspImg => {
type => 'text',
......@@ -665,7 +664,7 @@ sub attributes {
type => 'text',
default => "'self'",
documentation =>
'Authorized Ajax destination for Content-Security-Policy',
'Authorized Ajax destination for Content-Security-Policy',
},
cspFont => {
type => 'text',
......@@ -688,7 +687,7 @@ sub attributes {
documentation => 'Regular expression to create a random password',
},
trustedDomains =>
{ type => 'text', documentation => 'Trusted domains', },
{ type => 'text', documentation => 'Trusted domains', },
storePassword => {
default => 0,
type => 'bool',
......@@ -829,10 +828,10 @@ sub attributes {
flags => 'hp',
},
domain => {
type => 'text',
test => qr/^(?:$Regexp::Common::URI::RFC2396::hostname)?$/,
msgFail => '__badDomainName__',
default => 'example.com',
type => 'text',
test => qr/^(?:$Regexp::Common::URI::RFC2396::hostname)?$/,
msgFail => '__badDomainName__',
default => 'example.com',
documentation => 'DNS domain',
flags => 'hp',
},
......@@ -927,7 +926,7 @@ sub attributes {
groups => {
type => 'keyTextContainer',
help =>
'exportedvars.html#extend_variables_using_macros_and_groups',
'exportedvars.html#extend_variables_using_macros_and_groups',
test => $perlExpr,
default => {},
documentation => 'Groups',
......@@ -935,7 +934,7 @@ sub attributes {
macros => {
type => 'keyTextContainer',
help =>
'exportedvars.html#extend_variables_using_macros_and_groups',
'exportedvars.html#extend_variables_using_macros_and_groups',
keyTest => qr/^[_a-zA-Z][a-zA-Z0-9_]*$/,
keyMsgFail => '__badMacroName__',
test => $perlExpr,
......@@ -956,7 +955,7 @@ sub attributes {
'Directory' => '/var/lib/lemonldap-ng/sessions/',
'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock/',
'generateModule' =>
'Lemonldap::NG::Common::Apache::Session::Generate::SHA256',
'Lemonldap::NG::Common::Apache::Session::Generate::SHA256',
},
documentation => 'Session backend module options',
flags => 'hp',
......@@ -1055,11 +1054,11 @@ sub attributes {
test => sub {
my ( $val, $conf ) = @_;
return 1
if ( defined $conf->{macros}->{$val}
if ( defined $conf->{macros}->{$val}
or $val eq '_timezone' );
foreach ( keys %$conf ) {
return 1
if ( $_ =~ /exportedvars$/i
if ( $_ =~ /exportedvars$/i
and defined $conf->{$_}->{$val} );
}
return ( 1, "__unknownAttrOrMacro__: $val" );
......@@ -1075,9 +1074,10 @@ sub attributes {
documentation => 'Send a mail when password is changed',
},
portalRequireOldPassword => {
default => 1,
type => 'bool',
documentation => 'Old password is required to change the password',
default => 1,
type => 'bool',
documentation =>
'Old password is required to change the password',
},
hideOldPassword => {
default => 0,
......@@ -1085,51 +1085,11 @@ sub attributes {
documentation => 'Hide old password in portal',
},
# Mails
mailBody =>
{ type => 'longtext', documentation => 'Custom mail body', },
mailCharset => {
type => 'text',
default => 'utf-8',
documentation => 'Mail charset',
},
mailConfirmBody => {
type => 'longtext',
documentation => 'Custom confirm mail body',
},
mailConfirmSubject => {
type => 'text',
documentation => 'Mail subject for reset confirmation',
},
mailFrom => {
type => 'text',
default => 'noreply@example.com',
documentation => 'Sender email',
},
mailReplyTo => { type => 'text', documentation => 'Reply-To address' },
mailSessionKey => {
type => 'text',
default => 'mail',
documentation => 'Session parameter where mail is stored',
},
mailSubject => {
type => 'text',
documentation => 'Mail subject for new password email',
},
mailTimeout => {
type => 'int',
default => 0,
documentation => 'Mail session timeout',
},
mailUrl => {
type => 'url',
default => 'http://auth.example.com/resetpwd',
documentation => 'URL of password reset page',
},
# SMTP server
SMTPServer => {
type => 'text',
default => '',
test => qr/^(?:$Regexp::Common::URI::RFC2396::host(?::\d+)?)?$/,
test => qr/^(?:$Regexp::Common::URI::RFC2396::host(?::\d+)?)?$/,
documentation => 'SMTP Server',