Merge branch 'master' of gitlab.ow2.org:lemonldap-ng/lemonldap-ng

This commit is contained in:
Christophe Maudoux 2019-01-18 22:06:24 +01:00
commit 7e9aaea6bc
14 changed files with 187 additions and 139 deletions

View File

@ -70,6 +70,7 @@ describe('01 Lemonldap::NG Manager', function() {
}); });
it('General Parameters > Authn. parameters > Users modules => Should have 7 modules availabled with "Same" selected', function() { it('General Parameters > Authn. parameters > Users modules => Should have 7 modules availabled with "Same" selected', function() {
element(by.id('t-userDB')).click(); element(by.id('t-userDB')).click();
browser.sleep(1000);
expect(element(by.css('option[selected="selected"]')).getAttribute('Value')).toEqual('Same'); expect(element(by.css('option[selected="selected"]')).getAttribute('Value')).toEqual('Same');
expect(element.all(by.repeater('item in currentNode.select')).count()).toEqual(7); expect(element.all(by.repeater('item in currentNode.select')).count()).toEqual(7);
}); });

View File

@ -44,7 +44,7 @@ describe('05 Lemonldap::NG Manager', function() {
['exportedVars', 'macros', 'groups'].forEach(function(type) { ['exportedVars', 'macros', 'groups'].forEach(function(type) {
element(by.id('a-' + type)).click(); element(by.id('a-' + type)).click();
element(by.id('t-' + type)).click(); element(by.id('t-' + type)).click();
element(by.css('.glyphicon-plus-sign')).click(); element.all(by.css('.glyphicon-plus-sign')).first().click();
expect(element(by.id('t-' + type + '/n' + id)).getText()).toEqual('new'); expect(element(by.id('t-' + type + '/n' + id)).getText()).toEqual('new');
browser.sleep(3000); browser.sleep(3000);
id++; id++;

View File

@ -7,14 +7,19 @@ describe('06 Lemonldap::NG Manager', function() {
describe('Form control, part 2', function() { describe('Form control, part 2', function() {
it('should display portal skin choice', function() { it('should display portal skin choice', function() {
browser.get('/#/confs/1'); browser.get('/#!/confs/lastest');
element(by.id('a-generalParameters')).click(); element(by.id('a-generalParameters')).click();
element(by.id('a-portalParams')).click(); element(by.id('a-portalParams')).click();
element(by.id('a-portalCustomization')).click(); element(by.id('a-portalCustomization')).click();
element(by.id('t-portalSkin')).click(); element(by.id('t-portalSkin')).click();
element(by.css('[ng-click="showModal(\'portalSkinChoice.html\')"]')).click(); element(by.css('[ng-click="showModal(\'portalSkinChoice.html\')"]')).click();
browser.sleep(1000);
var skinChoice = element.all(by.repeater('b in currentNode.select')); var skinChoice = element.all(by.repeater('b in currentNode.select'));
expect(skinChoice.count()).toEqual(1); expect(skinChoice.count()).toEqual(1);
element(by.css('[trspan="cancel"]')).click();
browser.sleep(1000);
}); });
}); });
}); });

View File

@ -7,37 +7,57 @@ describe('07 Lemonldap::NG Manager', function() {
describe('Form control, part 3 - authParams', function() { describe('Form control, part 3 - authParams', function() {
it('should display auth modules chosen', function() { it('should display auth modules chosen', function() {
browser.get('/#/confs/1'); browser.get('/#!/confs/latest');
browser.sleep(2000);
element(by.id('a-generalParameters')).click(); element(by.id('a-generalParameters')).click();
browser.sleep(1000);
element(by.id('a-authParams')).click(); element(by.id('a-authParams')).click();
browser.sleep(1000);
element(by.id('t-authentication')).click(); element(by.id('t-authentication')).click();
browser.sleep(2000);
expect(element(by.id('t-demoParams')).isDisplayed()).toBeTruthy(); expect(element(by.id('t-demoParams')).isDisplayed()).toBeTruthy();
element(by.xpath("//option[@value='Apache']")).click(); element(by.xpath("//option[@value='Apache']")).click();
browser.sleep(2000);
expect(element(by.id('t-apacheParams')).isDisplayed()).toBeTruthy(); expect(element(by.id('t-apacheParams')).isDisplayed()).toBeTruthy();
}); });
it('should display auth modules chosen with authChoice', function() { it('should display auth modules chosen with authChoice', function() {
element(by.xpath("//option[@value='Choice']")).click(); element(by.xpath("//option[@value='Choice']")).click();
browser.sleep(1000);
expect(element(by.id('t-choiceParams')).isDisplayed()).toBeTruthy(); expect(element(by.id('t-choiceParams')).isDisplayed()).toBeTruthy();
element(by.id('a-choiceParams')).click(); element(by.id('a-choiceParams')).click();
browser.sleep(1000);
element(by.id('t-authChoiceModules')).click(); element(by.id('t-authChoiceModules')).click();
element(by.css('.glyphicon-plus-sign')).click(); browser.sleep(2000);
//element(by.css('.glyphicon-plus-sign')).click();
browser.sleep(2000);
element(by.id('a-authChoiceModules')).click(); element(by.id('a-authChoiceModules')).click();
browser.sleep(2000);
element.all(by.css('.glyphicon-plus-sign')).first().click();
element(by.id('t-authChoiceModules/n1')).click(); element(by.id('t-authChoiceModules/n1')).click();
element(by.xpath("//option[@value='LDAP']")).click(); browser.sleep(2000);
element.all(by.xpath("//option[@value='LDAP']")).first().click();
expect(element(by.id('t-ldapParams')).isDisplayed()).toBeTruthy(); expect(element(by.id('t-ldapParams')).isDisplayed()).toBeTruthy();
}); });
it('should display auth modules chosen with authCombination', function() { it('should display auth modules chosen with authCombination', function() {
element(by.id('t-authentication')).click(); element(by.id('t-authentication')).click();
browser.sleep(1000);
element(by.xpath("//option[@value='Combination']")).click(); element(by.xpath("//option[@value='Combination']")).click();
browser.sleep(1000);
expect(element(by.id('t-combinationParams')).isDisplayed()).toBeTruthy(); expect(element(by.id('t-combinationParams')).isDisplayed()).toBeTruthy();
element(by.id('a-combinationParams')).click(); element(by.id('a-combinationParams')).click();
browser.sleep(1000);
element(by.id('t-combModules')).click(); element(by.id('t-combModules')).click();
browser.sleep(2000);
element(by.css('.glyphicon-plus-sign')).click(); element(by.css('.glyphicon-plus-sign')).click();
element(by.xpath("//option[@value='DBI']")).click(); element(by.xpath("//option[@value='DBI']")).click();
expect(element(by.id('t-dbiParams')).isDisplayed()).toBeTruthy(); expect(element(by.id('t-dbiParams')).isDisplayed()).toBeTruthy();
element(by.xpath("//option[@value='LDAP']")).click(); element.all(by.xpath("//option[@value='LDAP']")).first().click();
expect(element(by.id('t-ldapParams')).isDisplayed()).toBeTruthy(); expect(element(by.id('t-ldapParams')).isDisplayed()).toBeTruthy();
}); });
}); });

View File

@ -7,7 +7,7 @@ describe('07u Lemonldap::NG Manager', function() {
describe('Apply mechanism', function() { describe('Apply mechanism', function() {
it('should be able to send UTF-8 chars', function() { it('should be able to send UTF-8 chars', function() {
browser.get('/#/confs/latest'); browser.get('/#!/confs/latest');
element(by.id('a-generalParameters')).click(); element(by.id('a-generalParameters')).click();
element(by.id('a-advancedParams')).click(); element(by.id('a-advancedParams')).click();
element(by.id('a-security')).click(); element(by.id('a-security')).click();
@ -18,6 +18,8 @@ describe('07u Lemonldap::NG Manager', function() {
element(by.id('save')).click(); element(by.id('save')).click();
element(by.id('longtextinput')).sendKeys('UTF-8 tests'); element(by.id('longtextinput')).sendKeys('UTF-8 tests');
element(by.id('saveok')).click(); element(by.id('saveok')).click();
browser.sleep(2000);
element(by.id('messageok')).click(); element(by.id('messageok')).click();
expect(element(by.id('cfgnum')).getText()).toEqual('2'); expect(element(by.id('cfgnum')).getText()).toEqual('2');
}); });

View File

@ -7,25 +7,38 @@ describe('08 Lemonldap::NG Manager', function() {
describe('Apply mechanism', function() { describe('Apply mechanism', function() {
it('should be able to add reload urls', function() { it('should be able to add reload urls', function() {
browser.get('/#/confs/latest'); browser.get('/#!/confs/latest');
browser.sleep(1000);
element(by.id('a-generalParameters')).click(); element(by.id('a-generalParameters')).click();
element(by.id('t-reloadParams')).click(); element(by.id('a-reloadParams')).click();
element(by.id('t-reloadUrls')).click(); element(by.id('t-reloadUrls')).click();
element(by.id('a-reloadUrls')).click();
browser.sleep(1000);
//element(by.id('a-reloadUrls')).click();
element(by.css('.glyphicon-plus-sign')).click(); element(by.css('.glyphicon-plus-sign')).click();
element(by.id('a-reloadUrls')).click(); browser.sleep(1000);
element(by.id('t-reloadUrls/n1')).click(); element(by.id('t-reloadUrls/n1')).click();
element(by.id('hashkeyinput')).clear().sendKeys('auth.example.com:19876'); browser.sleep(1000);
element(by.id('hashvalueinput')).clear().sendKeys('http://auth.example.com:19876/static/nothing'); element(by.id('hashkeyinput')).clear().sendKeys('auth.example.com');
browser.sleep(1000);
element(by.id('hashvalueinput')).clear().sendKeys('http://auth.example.com:19876/static/common/icons/ok.png');
browser.sleep(1000);
element(by.css('.glyphicon-plus-sign')).click(); element(by.css('.glyphicon-plus-sign')).click();
element(by.id('t-reloadUrls/n2')).click(); element(by.id('t-reloadUrls/n2')).click();
element(by.id('hashkeyinput')).clear().sendKeys('manager.example.com:19876'); element(by.id('hashkeyinput')).clear().sendKeys('manager.example.com');
element(by.id('hashvalueinput')).clear().sendKeys('http://auth.example.com:19876/static/js/manager.js'); element(by.id('hashvalueinput')).clear().sendKeys('http://manager.example.com:19876/static/js/manager.js');
browser.sleep(1000);
}); });
it('should save new configuration', function() { it('should save new configuration', function() {
element(by.id('save')).click(); element(by.id('save')).click();
element(by.id('longtextinput')).sendKeys('Reload URLs test'); element(by.id('longtextinput')).sendKeys('Reload URLs test');
element(by.id('saveok')).click(); element(by.id('saveok')).click();
expect(element.all(by.repeater('item in item.items')).count()).toEqual(2); expect(element.all(by.repeater('item in item.items')).count()).toEqual(2);
browser.sleep(1000);
element(by.id('messageok')).click(); element(by.id('messageok')).click();
expect(element(by.id('cfgnum')).getText()).toEqual('3'); expect(element(by.id('cfgnum')).getText()).toEqual('3');
}); });

View File

@ -9,7 +9,7 @@ describe('11 Lemonldap::NG Manager', function() {
it('should add an OIDC OP', function() { it('should add an OIDC OP', function() {
browser.get('/#/confs/latest'); browser.get('/#/confs/latest');
element(by.id('t-oidcOPMetaDataNodes')).click(); element(by.id('t-oidcOPMetaDataNodes')).click();
element(by.css('.glyphicon-plus-sign')).click(); element.all(by.css('.glyphicon-plus-sign')).first().click();
element(by.id('promptok')).click(); element(by.id('promptok')).click();
browser.sleep(500); browser.sleep(500);
element(by.id('a-oidcOPMetaDataNodes/new__op-example')).click(); element(by.id('a-oidcOPMetaDataNodes/new__op-example')).click();
@ -18,7 +18,7 @@ describe('11 Lemonldap::NG Manager', function() {
element(by.id('t-oidcOPMetaDataNodes/new__op-example/oidcOPMetaDataJWKS')).click(); element(by.id('t-oidcOPMetaDataNodes/new__op-example/oidcOPMetaDataJWKS')).click();
element(by.id('filetext')).sendKeys('{"c":"d"}'); element(by.id('filetext')).sendKeys('{"c":"d"}');
element(by.id('t-oidcOPMetaDataNodes/new__op-example/oidcOPMetaDataExportedVars')).click(); element(by.id('t-oidcOPMetaDataNodes/new__op-example/oidcOPMetaDataExportedVars')).click();
element(by.css('.glyphicon-plus-sign')).click(); element.all(by.css('.glyphicon-plus-sign')).first().click();
//element(by.id('a-oidcOPMetaDataNodes/new__op-example/oidcOPMetaDataExportedVars')).click(); //element(by.id('a-oidcOPMetaDataNodes/new__op-example/oidcOPMetaDataExportedVars')).click();
element(by.id('t-oidcOPMetaDataNodes/new__op-example/oidcOPMetaDataExportedVars/n1')).click(); element(by.id('t-oidcOPMetaDataNodes/new__op-example/oidcOPMetaDataExportedVars/n1')).click();
element(by.id('hashkeyinput')).clear().sendKeys('MyKey'); element(by.id('hashkeyinput')).clear().sendKeys('MyKey');

View File

@ -9,12 +9,12 @@ describe('12 Lemonldap::NG Manager', function() {
it('should add an OIDC RP', function() { it('should add an OIDC RP', function() {
browser.get('/#/confs/latest'); browser.get('/#/confs/latest');
element(by.id('t-oidcRPMetaDataNodes')).click(); element(by.id('t-oidcRPMetaDataNodes')).click();
element(by.css('.glyphicon-plus-sign')).click(); element.all(by.css('.glyphicon-plus-sign')).first().click();
element(by.id('promptok')).click(); element(by.id('promptok')).click();
browser.sleep(500); browser.sleep(500);
element(by.id('a-oidcRPMetaDataNodes/new__rp-example')).click(); element(by.id('a-oidcRPMetaDataNodes/new__rp-example')).click();
element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataExportedVars')).click(); element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataExportedVars')).click();
element(by.css('.glyphicon-plus-sign')).click(); element.all(by.css('.glyphicon-plus-sign')).first().click();
//element(by.id('a-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataExportedVars')).click(); //element(by.id('a-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataExportedVars')).click();
element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataExportedVars/n1')).click(); element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataExportedVars/n1')).click();
element(by.id('hashkeyinput')).clear().sendKeys('MyKey'); element(by.id('hashkeyinput')).clear().sendKeys('MyKey');
@ -24,7 +24,7 @@ describe('12 Lemonldap::NG Manager', function() {
element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataOptionsClientID')).click(); element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataOptionsClientID')).click();
element(by.id('textinput')).clear().sendKeys('MyClientID'); element(by.id('textinput')).clear().sendKeys('MyClientID');
element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataOptionsExtraClaims')).click(); element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataOptionsExtraClaims')).click();
element(by.css('.glyphicon-plus-sign')).click(); element.all(by.css('.glyphicon-plus-sign')).first().click();
//element(by.id('a-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataOptionsExtraClaims')).click(); //element(by.id('a-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataOptionsExtraClaims')).click();
element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataOptionsExtraClaims/n2')).click(); element(by.id('t-oidcRPMetaDataNodes/new__rp-example/oidcRPMetaDataOptionsExtraClaims/n2')).click();
element(by.id('hashkeyinput')).clear().sendKeys('MyClaim'); element(by.id('hashkeyinput')).clear().sendKeys('MyClaim');

View File

@ -7,7 +7,9 @@ describe('36 Lemonldap::NG Manager', function() {
describe('Diff interface', function() { describe('Diff interface', function() {
it('should find key changed', function() { it('should find key changed', function() {
browser.get('/diff.html#!/6/7'); browser.get('/diff.html#!/5/6');
browser.sleep(5000);
element(by.id('t-generalParameters')).click(); element(by.id('t-generalParameters')).click();
element(by.id('t-advancedParams')).click(); element(by.id('t-advancedParams')).click();
element(by.id('t-security')).click(); element(by.id('t-security')).click();

View File

@ -6,7 +6,7 @@ describe('40 Lemonldap::NG Manager', function() {
browser.get('/'); browser.get('/');
var links = element.all(by.repeater('l in links')); var links = element.all(by.repeater('l in links'));
expect(links.count()).toEqual(4); expect(links.count()).toEqual(4);
element(by.xpath("//a[@href='sessions.html']")).click(); element.all(by.xpath("//a[@href='sessions.html']")).first().click();
}); });
}); });

View File

@ -1,10 +1,10 @@
exports.config = { exports.config = {
allScriptsTimeout: 11000, allScriptsTimeout: 300000,
// Specific test // Specific test
specs: process.env.E2E_TESTS, // specs: process.env.E2E_TESTS,
// All tests // All tests
//specs: ['handler/*.js', 'portal/*.js', 'manager/*.js' ], specs: ['portal/*.js', 'handler/*.js', 'manager/*.js' ],
capabilities: { capabilities: {
//'browserName': 'firefox' //'browserName': 'firefox'
@ -18,6 +18,6 @@ exports.config = {
framework: 'jasmine', framework: 'jasmine',
jasmineNodeOpts: { jasmineNodeOpts: {
defaultTimeoutInterval: 30000 defaultTimeoutInterval: 60000
} }
}; };

View File

@ -1,6 +1,6 @@
package Lemonldap::NG::Handler::Main::Init; package Lemonldap::NG::Handler::Main::Init;
our $VERSION = '2.0.0'; our $VERSION = '2.0.2';
package Lemonldap::NG::Handler::Main; package Lemonldap::NG::Handler::Main;
@ -66,7 +66,9 @@ sub logLevelInit {
# adapt server signature # adapt server signature
sub serverSignatureInit { sub serverSignatureInit {
my $class = shift; my $class = shift;
$class->setServerSignature("Lemonldap::NG/$VERSION"); require Lemonldap::NG::Handler;
my $version = $Lemonldap::NG::Handler::VERSION;
$class->setServerSignature("Lemonldap::NG/$version");
} }
## @ifn protected void statusInit() ## @ifn protected void statusInit()
@ -107,7 +109,7 @@ sub statusInit {
exec $perl_exec, '-MLemonldap::NG::Handler::Lib::Status', exec $perl_exec, '-MLemonldap::NG::Handler::Lib::Status',
# Insert @INC in Perl path # Insert @INC in Perl path
map( { "-I$_" } @INC ), map( {"-I$_"} @INC ),
# Command to launch # Command to launch
'-e', '&Lemonldap::NG::Handler::Lib::Status::run()', '-e', '&Lemonldap::NG::Handler::Lib::Status::run()',

View File

@ -30,7 +30,8 @@ sub tests {
portalIsInDomain => sub { portalIsInDomain => sub {
return ( return (
1, 1,
( index( $conf->{portal}, $conf->{domain} ) > 0 (
index( $conf->{portal}, $conf->{domain} ) > 0
? '' ? ''
: "Portal seems not to be in the domain $conf->{domain}" : "Portal seems not to be in the domain $conf->{domain}"
) )
@ -42,7 +43,7 @@ sub tests {
# Checking for ending slash # Checking for ending slash
$conf->{portal} .= '/' $conf->{portal} .= '/'
unless ( $conf->{portal} =~ qr#/$# ); unless ( $conf->{portal} =~ qr#/$# );
# Deleting trailing ending slash # Deleting trailing ending slash
my $regex = qr#/+$#; my $regex = qr#/+$#;
@ -60,10 +61,11 @@ sub tests {
} }
return ( return (
1, 1,
( @pb (
@pb
? 'Virtual hosts ' ? 'Virtual hosts '
. join( ', ', @pb ) . join( ', ', @pb )
. " are not in $conf->{domain} and cross-domain-authentication is not set" . " are not in $conf->{domain} and cross-domain-authentication is not set"
: undef : undef
) )
); );
@ -77,9 +79,9 @@ sub tests {
} }
if (@pb) { if (@pb) {
return ( 0, return ( 0,
'Virtual hosts ' 'Virtual hosts '
. join( ', ', @pb ) . join( ', ', @pb )
. " contain a port, this is not allowed" ); . " contain a port, this is not allowed" );
} }
else { return 1; } else { return 1; }
}, },
@ -92,9 +94,9 @@ sub tests {
} }
if (@pb) { if (@pb) {
return ( 0, return ( 0,
'Virtual hosts ' 'Virtual hosts '
. join( ', ', @pb ) . join( ', ', @pb )
. " must be in lower case" ); . " must be in lower case" );
} }
else { return 1; } else { return 1; }
}, },
@ -102,12 +104,12 @@ sub tests {
# Check if "userDB" and "authentication" are consistent # Check if "userDB" and "authentication" are consistent
authAndUserDBConsistency => sub { authAndUserDBConsistency => sub {
foreach foreach
my $type (qw(Facebook Google OpenID OpenIDConnect SAML WebID)) my $type (qw(Facebook Google OpenID OpenIDConnect SAML WebID))
{ {
return ( 0, return ( 0,
"\"$type\" can not be used as user database without using \"$type\" for authentication" "\"$type\" can not be used as user database without using \"$type\" for authentication"
) )
if ($conf->{userDB} =~ /$type/ if ( $conf->{userDB} =~ /$type/
and $conf->{authentication} !~ /$type/ ); and $conf->{authentication} !~ /$type/ );
} }
return 1; return 1;
@ -117,29 +119,30 @@ sub tests {
checkAttrAndMacros => sub { checkAttrAndMacros => sub {
my @tmp; my @tmp;
foreach my $k ( keys %$conf ) { foreach my $k ( keys %$conf ) {
if ( $k if ( $k =~
=~ /^(?:openIdSreg_(?:(?:(?:full|nick)nam|languag|postcod|timezon)e|country|gender|email|dob)|whatToTrace)$/ /^(?:openIdSreg_(?:(?:(?:full|nick)nam|languag|postcod|timezon)e|country|gender|email|dob)|whatToTrace)$/
) )
{ {
my $v = $conf->{$k}; my $v = $conf->{$k};
$v =~ s/^$//; $v =~ s/^$//;
next if ( $v =~ /^_/ ); next if ( $v =~ /^_/ );
push @tmp, push @tmp,
$k $k
unless ( unless (
defined( defined(
$conf->{exportedVars}->{$v} $conf->{exportedVars}->{$v}
or defined( $conf->{macros}->{$v} ) or defined( $conf->{macros}->{$v} )
) )
); );
} }
} }
return ( return (
1, 1,
( @tmp (
@tmp
? 'Values of parameter(s) "' ? 'Values of parameter(s) "'
. join( ', ', @tmp ) . join( ', ', @tmp )
. '" are not defined in exported attributes or macros' . '" are not defined in exported attributes or macros'
: '' : ''
) )
); );
@ -151,18 +154,18 @@ sub tests {
if ( $conf->{userDB} =~ /^Google$/ ) { if ( $conf->{userDB} =~ /^Google$/ ) {
foreach my $k ( keys %{ $conf->{exportedVars} } ) { foreach my $k ( keys %{ $conf->{exportedVars} } ) {
my $v = $conf->{exportedVars}->{$k}; my $v = $conf->{exportedVars}->{$k};
if ( $v !~ Lemonldap::NG::Common::Regexp::GOOGLEAXATTR() ) if ( $v !~ Lemonldap::NG::Common::Regexp::GOOGLEAXATTR() ) {
{
push @tmp, $v; push @tmp, $v;
} }
} }
} }
return ( return (
1, 1,
( @tmp (
@tmp
? 'Values of parameter(s) "' ? 'Values of parameter(s) "'
. join( ', ', @tmp ) . join( ', ', @tmp )
. '" are not exported by Google' . '" are not exported by Google'
: '' : ''
) )
); );
@ -174,8 +177,7 @@ sub tests {
if ( $conf->{userDB} =~ /^OpenID$/ ) { if ( $conf->{userDB} =~ /^OpenID$/ ) {
foreach my $k ( keys %{ $conf->{exportedVars} } ) { foreach my $k ( keys %{ $conf->{exportedVars} } ) {
my $v = $conf->{exportedVars}->{$k}; my $v = $conf->{exportedVars}->{$k};
if ( $v if ( $v !~ Lemonldap::NG::Common::Regexp::OPENIDSREGATTR() )
!~ Lemonldap::NG::Common::Regexp::OPENIDSREGATTR() )
{ {
push @tmp, $v; push @tmp, $v;
} }
@ -183,10 +185,11 @@ sub tests {
} }
return ( return (
1, 1,
( @tmp (
@tmp
? 'Values of parameter(s) "' ? 'Values of parameter(s) "'
. join( ', ', @tmp ) . join( ', ', @tmp )
. '" are not exported by OpenID SREG' . '" are not exported by OpenID SREG'
: '' : ''
) )
); );
@ -195,51 +198,51 @@ sub tests {
# Try to use Apache::Session module # Try to use Apache::Session module
testApacheSession => sub { testApacheSession => sub {
my ( $id, %h ); my ( $id, %h );
my $gc = Lemonldap::NG::Handler::Main->tsv my $gc = Lemonldap::NG::Handler::Main->tsv->{sessionStorageModule};
->{sessionStorageModule};
return 1 return 1
if ( ( $gc and $gc eq $conf->{globalStorage} ) if ( ( $gc and $gc eq $conf->{globalStorage} )
or $conf->{globalStorage} or $conf->{globalStorage} =~
=~ /^Lemonldap::NG::Common::Apache::Session::/ ); /^Lemonldap::NG::Common::Apache::Session::/ );
eval "use $conf->{globalStorage}"; eval "use $conf->{globalStorage}";
return ( -1, "Unknown package $conf->{globalStorage}" ) if ($@); return ( -1, "Unknown package $conf->{globalStorage}" ) if ($@);
eval { eval {
tie %h, 'Lemonldap::NG::Common::Apache::Session', undef, tie %h, 'Lemonldap::NG::Common::Apache::Session', undef,
{ {
%{ $conf->{globalStorageOptions} }, %{ $conf->{globalStorageOptions} },
backend => $conf->{globalStorage} backend => $conf->{globalStorage}
}; };
}; };
return ( -1, "Unable to create a session ($@)" ) return ( -1, "Unable to create a session ($@)" )
if ( $@ or not tied(%h) ); if ( $@ or not tied(%h) );
eval { eval {
$h{a} = 1; $h{a} = 1;
$id = $h{_session_id} or return ( -1, 'No _session_id' ); $id = $h{_session_id} or return ( -1, 'No _session_id' );
untie(%h); untie(%h);
tie %h, 'Lemonldap::NG::Common::Apache::Session', $id, tie %h, 'Lemonldap::NG::Common::Apache::Session', $id,
{ {
%{ $conf->{globalStorageOptions} }, %{ $conf->{globalStorageOptions} },
backend => $conf->{globalStorage} backend => $conf->{globalStorage}
}; };
}; };
return ( -1, "Unable to insert data ($@)" ) if ($@); return ( -1, "Unable to insert data ($@)" ) if ($@);
return ( -1, "Unable to recover data stored" ) return ( -1, "Unable to recover data stored" )
unless ( $h{a} == 1 ); unless ( $h{a} == 1 );
eval { tied(%h)->delete; }; eval { tied(%h)->delete; };
return ( -1, "Unable to delete session ($@)" ) if ($@); return ( -1, "Unable to delete session ($@)" ) if ($@);
return ( -1, 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 Apache servers'
) if ( $gc and $conf->{globalStorage} ne $gc ); ) if ( $gc and $conf->{globalStorage} ne $gc );
return 1; return 1;
}, },
# Warn if cookie name has changed # Warn if cookie name has changed
cookieNameChanged => sub { cookieNameChanged => sub {
my $cn = $Lemonldap::NG::Handler::PSGI::API::tsv->{cookieName}; my $cn = Lemonldap::NG::Handler::Main->tsv->{cookieName};
return ( return (
1, 1,
( $cn (
and $cn ne $conf->{cookieName} $cn
and $cn ne $conf->{cookieName}
? 'Cookie name has changed, you must restart all your web servers' ? 'Cookie name has changed, you must restart all your web servers'
: () : ()
) )
@ -250,9 +253,10 @@ sub tests {
cookieTTL => sub { cookieTTL => sub {
return 1 unless ( defined $conf->{cookieExpiration} ); return 1 unless ( defined $conf->{cookieExpiration} );
return ( 0, "Cookie TTL must be higher than one minute" ) return ( 0, "Cookie TTL must be higher than one minute" )
unless ( $conf->{cookieExpiration} == 0 || $conf->{cookieExpiration} > 60 ); unless ( $conf->{cookieExpiration} == 0
|| $conf->{cookieExpiration} > 60 );
return ( 1, "Cookie TTL should be higher or equal than one hour" ) return ( 1, "Cookie TTL should be higher or equal than one hour" )
unless ( $conf->{cookieExpiration} >= 3600 unless ( $conf->{cookieExpiration} >= 3600
|| $conf->{cookieExpiration} == 0 ); || $conf->{cookieExpiration} == 0 );
# Return # Return
@ -263,7 +267,7 @@ sub tests {
sessionTimeout => sub { sessionTimeout => sub {
return 1 unless ( defined $conf->{timeout} ); 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 unless ( $conf->{timeout} > 600
|| $conf->{timeout} == 0 ); || $conf->{timeout} == 0 );
# Return # Return
@ -274,9 +278,9 @@ sub tests {
sessionTimeoutActivity => sub { sessionTimeoutActivity => sub {
return 1 unless ( defined $conf->{timeoutActivity} ); return 1 unless ( defined $conf->{timeoutActivity} );
return ( 0, return ( 0,
"Session activity timeout must be higher or equal than one minute" "Session activity timeout must be higher or equal than one minute"
) )
unless ( $conf->{timeoutActivity} > 59 unless ( $conf->{timeoutActivity} > 59
|| $conf->{timeoutActivity} == 0 ); || $conf->{timeoutActivity} == 0 );
# Return # Return
@ -287,11 +291,11 @@ sub tests {
timeoutActivityInterval => sub { timeoutActivityInterval => sub {
return 1 unless ( defined $conf->{timeoutActivityInterval} ); return 1 unless ( defined $conf->{timeoutActivityInterval} );
return ( 0, return ( 0,
"Activity timeout interval must be lower than session activity timeout" "Activity timeout interval must be lower than session activity timeout"
) )
if ($conf->{timeoutActivity} if ( $conf->{timeoutActivity}
and $conf->{timeoutActivity} and $conf->{timeoutActivity} <=
<= $conf->{timeoutActivityInterval} ); $conf->{timeoutActivityInterval} );
# Return # Return
return 1; return 1;
@ -301,7 +305,8 @@ sub tests {
managerProtection => sub { managerProtection => sub {
return ( return (
1, 1,
( $conf->{cfgAuthor} eq 'anonymous' (
$conf->{cfgAuthor} eq 'anonymous'
? 'Your manager seems to be unprotected' ? 'Your manager seems to be unprotected'
: '' : ''
) )
@ -317,21 +322,21 @@ sub tests {
# Use SMTP # Use SMTP
eval "use Net::SMTP"; eval "use Net::SMTP";
return ( 1, "Net::SMTP module is required to use SMTP server" ) return ( 1, "Net::SMTP module is required to use SMTP server" )
if ($@); if ($@);
# Create SMTP object # Create SMTP object
my $smtp = Net::SMTP->new( $conf->{SMTPServer}, Timeout => 5 ); my $smtp = Net::SMTP->new( $conf->{SMTPServer}, Timeout => 5 );
return ( 1, return ( 1,
"SMTP connection to " . $conf->{SMTPServer} . " failed" ) "SMTP connection to " . $conf->{SMTPServer} . " failed" )
unless ($smtp); unless ($smtp);
# Skip other tests if no authentication # Skip other tests if no authentication
return 1 return 1
unless ( $conf->{SMTPAuthUser} and $conf->{SMTPAuthPass} ); unless ( $conf->{SMTPAuthUser} and $conf->{SMTPAuthPass} );
# Try authentication # Try authentication
return ( 1, "SMTP authentication failed" ) return ( 1, "SMTP authentication failed" )
unless $smtp->auth( $conf->{SMTPAuthUser}, unless $smtp->auth( $conf->{SMTPAuthUser},
$conf->{SMTPAuthPass} ); $conf->{SMTPAuthPass} );
# Return # Return
@ -341,14 +346,15 @@ sub tests {
# SAML entity ID must be uniq # SAML entity ID must be uniq
samlIDPEntityIdUniqueness => sub { samlIDPEntityIdUniqueness => sub {
return 1 return 1
unless ( $conf->{samlIDPMetaDataXML} unless ( $conf->{samlIDPMetaDataXML}
and %{ $conf->{samlIDPMetaDataXML} } ); and %{ $conf->{samlIDPMetaDataXML} } );
my @msg; my @msg;
my $res = 1; my $res = 1;
my %entityIds; my %entityIds;
foreach my $idpId ( keys %{ $conf->{samlIDPMetaDataXML} } ) { foreach my $idpId ( keys %{ $conf->{samlIDPMetaDataXML} } ) {
unless ( $conf->{samlIDPMetaDataXML}->{$idpId} unless (
->{samlIDPMetaDataXML} =~ /entityID=(['"])(.+?)\1/si ) $conf->{samlIDPMetaDataXML}->{$idpId}->{samlIDPMetaDataXML}
=~ /entityID=(['"])(.+?)\1/si )
{ {
push @msg, "$idpId SAML metadata has no EntityID"; push @msg, "$idpId SAML metadata has no EntityID";
$res = 0; $res = 0;
@ -357,7 +363,7 @@ sub tests {
my $eid = $2; my $eid = $2;
if ( defined $entityIds{$eid} ) { if ( defined $entityIds{$eid} ) {
push @msg, push @msg,
"$idpId and $entityIds{$eid} have the same SAML EntityID"; "$idpId and $entityIds{$eid} have the same SAML EntityID";
$res = 0; $res = 0;
next; next;
} }
@ -367,15 +373,15 @@ sub tests {
}, },
samlSPEntityIdUniqueness => sub { samlSPEntityIdUniqueness => sub {
return 1 return 1
unless ( $conf->{samlSPMetaDataXML} unless ( $conf->{samlSPMetaDataXML}
and %{ $conf->{samlSPMetaDataXML} } ); and %{ $conf->{samlSPMetaDataXML} } );
my @msg; my @msg;
my $res = 1; my $res = 1;
my %entityIds; my %entityIds;
foreach my $spId ( keys %{ $conf->{samlSPMetaDataXML} } ) { foreach my $spId ( keys %{ $conf->{samlSPMetaDataXML} } ) {
unless ( unless (
$conf->{samlSPMetaDataXML}->{$spId}->{samlSPMetaDataXML} $conf->{samlSPMetaDataXML}->{$spId}->{samlSPMetaDataXML} =~
=~ /entityID=(['"])(.+?)\1/si ) /entityID=(['"])(.+?)\1/si )
{ {
push @msg, "$spId SAML metadata has no EntityID"; push @msg, "$spId SAML metadata has no EntityID";
$res = 0; $res = 0;
@ -384,7 +390,7 @@ sub tests {
my $eid = $2; my $eid = $2;
if ( defined $entityIds{$eid} ) { if ( defined $entityIds{$eid} ) {
push @msg, push @msg,
"$spId and $entityIds{$eid} have the same SAML EntityID"; "$spId and $entityIds{$eid} have the same SAML EntityID";
$res = 0; $res = 0;
next; next;
} }
@ -398,7 +404,7 @@ sub tests {
return 1 unless ( $conf->{authentication} eq 'Combination' ); return 1 unless ( $conf->{authentication} eq 'Combination' );
require Lemonldap::NG::Common::Combination::Parser; require Lemonldap::NG::Common::Combination::Parser;
return ( 0, 'No module declared for combination' ) return ( 0, 'No module declared for combination' )
unless ( $conf->{combModules} and %{ $conf->{combModules} } ); unless ( $conf->{combModules} and %{ $conf->{combModules} } );
my $moduleList; my $moduleList;
foreach my $md ( keys %{ $conf->{combModules} } ) { foreach my $md ( keys %{ $conf->{combModules} } ) {
my $entry = $conf->{combModules}->{$md}; my $entry = $conf->{combModules}->{$md};
@ -409,8 +415,8 @@ sub tests {
); );
} }
eval { eval {
Lemonldap::NG::Common::Combination::Parser->parse( Lemonldap::NG::Common::Combination::Parser->parse( $moduleList,
$moduleList, $conf->{combination} ); $conf->{combination} );
}; };
return ( 0, $@ ) if ($@); return ( 0, $@ ) if ($@);
@ -422,9 +428,9 @@ sub tests {
combinationParameters => sub { combinationParameters => sub {
return 1 unless ( $conf->{authentication} eq "Combination" ); return 1 unless ( $conf->{authentication} eq "Combination" );
return ( 0, "Combination rule must be defined" ) return ( 0, "Combination rule must be defined" )
unless ( $conf->{combination} ); unless ( $conf->{combination} );
return ( 0, 'userDB must be set to "Same" to enable Combination' ) return ( 0, 'userDB must be set to "Same" to enable Combination' )
unless ( $conf->{userDB} eq "Same" ); unless ( $conf->{userDB} eq "Same" );
# Return # Return
return 1; return 1;
@ -447,7 +453,7 @@ sub tests {
eval "use Convert::Base32"; eval "use Convert::Base32";
return ( 1, return ( 1,
"Convert::Base32 module is required to enable TOTP" ) "Convert::Base32 module is required to enable TOTP" )
if ($@); if ($@);
} }
# Use U2F # Use U2F
@ -456,7 +462,7 @@ sub tests {
{ {
eval "use Crypt::U2F::Server::Simple"; eval "use Crypt::U2F::Server::Simple";
return ( 1, return ( 1,
"Crypt::U2F::Server::Simple module is required to enable U2F" "Crypt::U2F::Server::Simple module is required to enable U2F"
) if ($@); ) if ($@);
} }
@ -464,7 +470,7 @@ sub tests {
if ( $conf->{yubikey2fActivation} ) { if ( $conf->{yubikey2fActivation} ) {
eval "use Auth::Yubikey_WebClient"; eval "use Auth::Yubikey_WebClient";
return ( 1, return ( 1,
"Auth::Yubikey_WebClient module is required to enable Yubikey" "Auth::Yubikey_WebClient module is required to enable Yubikey"
) if ($@); ) if ($@);
} }
@ -478,7 +484,7 @@ sub tests {
my $w = ""; my $w = "";
foreach ( 'totp', 'u' ) { foreach ( 'totp', 'u' ) {
$w .= uc($_) . "2F is activated twice \n" $w .= uc($_) . "2F is activated twice \n"
if ( $conf->{ $_ . '2fActivation' } eq '1' ); if ( $conf->{ $_ . '2fActivation' } eq '1' );
} }
return ( 1, ( $w ? $w : () ) ); return ( 1, ( $w ? $w : () ) );
}, },
@ -489,8 +495,10 @@ sub tests {
return 1 unless ( defined $conf->{totp2fDigits} ); return 1 unless ( defined $conf->{totp2fDigits} );
return ( return (
1, 1,
( ( $conf->{totp2fDigits} == 6 (
or $conf->{totp2fDigits} == 8 (
$conf->{totp2fDigits} == 6
or $conf->{totp2fDigits} == 8
) )
? '' ? ''
: 'TOTP should be 6 or 8 digits long' : 'TOTP should be 6 or 8 digits long'
@ -502,9 +510,9 @@ sub tests {
totp2fParams => sub { totp2fParams => sub {
return 1 unless ( $conf->{totp2fActivation} ); return 1 unless ( $conf->{totp2fActivation} );
return ( 0, 'TOTP range must be defined' ) return ( 0, 'TOTP range must be defined' )
unless ( $conf->{totp2fRange} ); unless ( $conf->{totp2fRange} );
return ( 1, "TOTP interval should be higher than 10s" ) return ( 1, "TOTP interval should be higher than 10s" )
unless ( $conf->{totp2fInterval} > 10 ); unless ( $conf->{totp2fInterval} > 10 );
# Return # Return
return 1; return 1;
@ -515,11 +523,12 @@ sub tests {
yubikey2fParams => sub { yubikey2fParams => sub {
return 1 unless ( $conf->{yubikey2fActivation} ); return 1 unless ( $conf->{yubikey2fActivation} );
return ( 0, "Yubikey client ID and secret key must be set" ) return ( 0, "Yubikey client ID and secret key must be set" )
unless ( defined $conf->{yubikey2fSecretKey} unless ( defined $conf->{yubikey2fSecretKey}
&& defined $conf->{yubikey2fClientID} ); && defined $conf->{yubikey2fClientID} );
return ( return (
1, 1,
( ( $conf->{yubikey2fPublicIDSize} == 12 ) (
( $conf->{yubikey2fPublicIDSize} == 12 )
? '' ? ''
: 'Yubikey public ID size should be 12 digits long' : 'Yubikey public ID size should be 12 digits long'
) )
@ -530,7 +539,7 @@ sub tests {
rest2fVerifyUrl => sub { rest2fVerifyUrl => sub {
return 1 unless ( $conf->{rest2fActivation} ); return 1 unless ( $conf->{rest2fActivation} );
return ( 0, "REST 2F Verify URL must be set" ) return ( 0, "REST 2F Verify URL must be set" )
unless ( defined $conf->{rest2fVerifyUrl} ); unless ( defined $conf->{rest2fVerifyUrl} );
# Return # Return
return 1; return 1;
@ -544,16 +553,15 @@ sub tests {
my $ok = 0; my $ok = 0;
foreach (qw(u totp yubikey)) { foreach (qw(u totp yubikey)) {
$ok ||= $conf->{ $_ . '2fActivation' } $ok ||= $conf->{ $_ . '2fActivation' }
&& $conf->{ $_ . '2fSelfRegistration' }; && $conf->{ $_ . '2fSelfRegistration' };
last if ($ok); last if ($ok);
} }
$ok ||= $conf->{'utotp2fActivation'} $ok ||= $conf->{'utotp2fActivation'}
&& ( $conf->{'u2fSelfRegistration'} && ( $conf->{'u2fSelfRegistration'}
|| $conf->{'totp2fSelfRegistration'} ); || $conf->{'totp2fSelfRegistration'} );
$msg $msg = "A self registrable module should be enabled to require 2FA"
= "A self registrable module should be enabled to require 2FA" unless ($ok);
unless ($ok);
return ( 1, $msg ); return ( 1, $msg );
}, },
@ -562,7 +570,7 @@ sub tests {
ext2fCommands => sub { ext2fCommands => sub {
return 1 unless ( $conf->{ext2fActivation} ); return 1 unless ( $conf->{ext2fActivation} );
return ( 0, "External 2F Send or Validate command must be set" ) return ( 0, "External 2F Send or Validate command must be set" )
unless ( defined $conf->{ext2FSendCommand} unless ( defined $conf->{ext2FSendCommand}
&& defined $conf->{ext2FValidateCommand} ); && defined $conf->{ext2FValidateCommand} );
# Return # Return
@ -573,9 +581,9 @@ sub tests {
formTimeout => sub { formTimeout => sub {
return 1 unless ( defined $conf->{formTimeout} ); return 1 unless ( defined $conf->{formTimeout} );
return ( 0, "XSRF form token TTL must be higher than 30s" ) return ( 0, "XSRF form token TTL must be higher than 30s" )
unless ( $conf->{formTimeout} > 30 ); unless ( $conf->{formTimeout} > 30 );
return ( 1, "XSRF form token TTL should not be higher than 2mn" ) return ( 1, "XSRF form token TTL should not be higher than 2mn" )
if ( $conf->{formTimeout} > 120 ); if ( $conf->{formTimeout} > 120 );
# Return # Return
return 1; return 1;
@ -584,9 +592,8 @@ sub tests {
# Warn if number of password reset retries is null # Warn if number of password reset retries is null
passwordResetRetries => sub { passwordResetRetries => sub {
return 1 unless ( $conf->{portalDisplayResetPassword} ); return 1 unless ( $conf->{portalDisplayResetPassword} );
return ( 1, return ( 1, "Number of reset password retries should not be null" )
"Number of reset password retries should not be null" ) unless ( $conf->{passwordResetAllowedRetries} );
unless ( $conf->{passwordResetAllowedRetries} );
# Return # Return
return 1; return 1;
@ -596,10 +603,10 @@ sub tests {
bruteForceProtection => sub { bruteForceProtection => sub {
return 1 unless ( $conf->{bruteForceProtection} ); return 1 unless ( $conf->{bruteForceProtection} );
return ( 1, return ( 1,
'"History" plugin is required to enable "BruteForceProtection" plugin' '"History" plugin is required to enable "BruteForceProtection" plugin'
) unless ( $conf->{loginHistoryEnabled} ); ) unless ( $conf->{loginHistoryEnabled} );
return ( 1, return ( 1,
'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin' 'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin'
) unless ( $conf->{failedLoginNumber} > 2 ); ) unless ( $conf->{failedLoginNumber} > 2 );
# Return # Return
@ -610,9 +617,9 @@ sub tests {
checkMailResetSecurity => sub { checkMailResetSecurity => sub {
return 1 unless ( $conf->{portalDisplayResetPassword} ); return 1 unless ( $conf->{portalDisplayResetPassword} );
return ( -1, return ( -1,
'"passwordMailReset" plugin is enabled without CSRF Token neither Captcha required !!!' '"passwordMailReset" plugin is enabled without CSRF Token neither Captcha required !!!'
) )
unless ( $conf->{requireToken} unless ( $conf->{requireToken}
or $conf->{captcha_mail_enabled} ); or $conf->{captcha_mail_enabled} );
# Return # Return

View File

@ -3,11 +3,10 @@
package Lemonldap::NG::Portal::Main::Menu; package Lemonldap::NG::Portal::Main::Menu;
use strict; use strict;
use utf8;
use Mouse; use Mouse;
use Clone 'clone'; use Clone 'clone';
our $VERSION = '2.0.1'; our $VERSION = '2.0.2';
extends 'Lemonldap::NG::Common::Module'; extends 'Lemonldap::NG::Common::Module';
@ -188,7 +187,6 @@ sub appslist {
sub _buildCategoryHash { sub _buildCategoryHash {
my ( $self, $req, $catid, $cathash, $catlevel ) = @_; my ( $self, $req, $catid, $cathash, $catlevel ) = @_;
my $catname = $cathash->{catname} || $catid; my $catname = $cathash->{catname} || $catid;
utf8::decode($catname);
my $applications; my $applications;
my $categories; my $categories;
@ -244,8 +242,6 @@ sub _buildApplicationHash {
my $appuri = $apphash->{options}->{uri} || ""; my $appuri = $apphash->{options}->{uri} || "";
my $appdesc = $apphash->{options}->{description}; my $appdesc = $apphash->{options}->{description};
my $applogo = $apphash->{options}->{logo}; my $applogo = $apphash->{options}->{logo};
utf8::decode($appname);
utf8::decode($appdesc) if $appdesc;
# Detect sub applications # Detect sub applications
my $subapphash; my $subapphash;