Merge branch 'v2.0'

This commit is contained in:
Xavier Guimard 2019-05-24 10:23:40 +02:00
commit 4678649367
26 changed files with 572 additions and 35 deletions

View File

@ -1,4 +1,5 @@
#
# Regular cron jobs for LemonLDAP::NG Handler
# Regular cron jobs for the Lemonldap::NG handler
# Launched only if systemd isn't running
#
1 * * * * www-data [ -x /usr/share/lemonldap-ng/bin/purgeLocalCache ] && /usr/share/lemonldap-ng/bin/purgeLocalCache
17-59/30 * * * * www-data [ -d /run/systemd/system ] || [ ! -x /usr/share/lemonldap-ng/bin/purgeLocalCache ] || /usr/share/lemonldap-ng/bin/purgeLocalCache

View File

@ -0,0 +1,10 @@
[Unit]
Description=Cron job for Lemonldap::NG handler
After=network.target
[Service]
User=www-data
ExecStart=/usr/share/lemonldap-ng/bin/purgeLocalCache
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,9 @@
[Unit]
Description=Purge Lemonldap::NG handler cache every 30 minutes
[Timer]
OnCalendar=*-*-* *:17,47:00
Persistent=true
[Install]
WantedBy=timers.target

View File

@ -1,4 +1,5 @@
#
# Regular cron jobs for LemonLDAP::NG Portal
# Regular cron jobs to clean Lemonldap::NG sessions DB
# Launched only if systemd isn't running
#
*/10 * * * * www-data [ -x /usr/share/lemonldap-ng/bin/purgeCentralCache ] && /usr/share/lemonldap-ng/bin/purgeCentralCache
7 * * * * www-data [ -d /run/systemd/system ] || [ ! -x /usr/share/lemonldap-ng/bin/purgeCentralCache ] || /usr/share/lemonldap-ng/bin/purgeCentralCache

View File

@ -0,0 +1,10 @@
[Unit]
Description=Cron job for Lemonldap::NG portal
After=network.target
[Service]
User=www-data
ExecStart=/usr/share/lemonldap-ng/bin/purgeCentralCache
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,9 @@
[Unit]
Description=Clean Lemonldap::NG sessions DB every 1h
[Timer]
OnCalendar=*-*-* *:07:07
Persistent=true
[Install]
WantedBy=timers.target

View File

@ -35,6 +35,7 @@ lib/Lemonldap/NG/Common/Conf/Serializer.pm
lib/Lemonldap/NG/Common/Conf/Wrapper.pm
lib/Lemonldap/NG/Common/Crypto.pm
lib/Lemonldap/NG/Common/FormEncode.pm
lib/Lemonldap/NG/Common/IO/Filter.pm
lib/Lemonldap/NG/Common/IPv6.pm
lib/Lemonldap/NG/Common/Logger/Apache2.pm
lib/Lemonldap/NG/Common/Logger/Dispatch.pm
@ -83,7 +84,10 @@ t/35-Common-Crypto.t
t/36-Common-Regexp.t
t/40-Common-Session.t
t/50-Combination-Parser.t
t/60-Common-IO-Filter.t
t/99-pod.t
t/inc.tpl
t/test.tpl
tools/apache-session-mysql.sql
tools/lmConfig.CDBI.mysql
tools/lmConfig.RDBI.mysql

View File

@ -1,6 +1,8 @@
Changes
eg/handler.psgi
eg/llng-server.psgi
eg/scripts/liblemonldap-ng-handler-perl.service
eg/scripts/llng-handler.systemd.timer
eg/scripts/purgeLocalCache
eg/scripts/purgeLocalCache.cron.d
lib/Lemonldap/NG/Handler.pm

View File

@ -0,0 +1,10 @@
[Unit]
Description=Cron job for Lemonldap::NG handler
After=network.target
[Service]
User=www-data
ExecStart=/usr/share/lemonldap-ng/bin/purgeLocalCache
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,9 @@
[Unit]
Description=Purge Lemonldap::NG handler cache every 30 minutes
[Timer]
OnCalendar=*-*-* *:17,47:00
Persistent=true
[Install]
WantedBy=timers.target

View File

@ -25,8 +25,7 @@ sub addRoutes {
my ( $self, $conf ) = @_;
$self->ua( Lemonldap::NG::Common::UserAgent->new($conf) );
my $hiddenKeys = '';
$hiddenKeys = $self->{viewerHiddenKeys};
my $hiddenKeys = $self->{viewerHiddenKeys} || '';
my @enabledKeys = ();
my @keys = qw(virtualHosts samlIDPMetaDataNodes samlSPMetaDataNodes
applicationList oidcOPMetaDataNodes oidcRPMetaDataNodes

View File

@ -163,6 +163,8 @@ site/coffee/sslChoice.coffee
site/coffee/totpregistration.coffee
site/coffee/u2fcheck.coffee
site/coffee/u2fregistration.coffee
site/cron/liblemonldap-ng-portal-perl.service
site/cron/llng-portal.systemd.timer
site/cron/purgeCentralCache
site/cron/purgeCentralCache.cron.d
site/htdocs/index.fcgi
@ -335,6 +337,7 @@ site/templates/bootstrap/2fregisters.tpl
site/templates/bootstrap/casBack2Url.tpl
site/templates/bootstrap/checklogins.tpl
site/templates/bootstrap/checkuser.tpl
site/templates/bootstrap/choice.tpl
site/templates/bootstrap/confirm.tpl
site/templates/bootstrap/customfooter.tpl
site/templates/bootstrap/customhead.tpl
@ -349,8 +352,10 @@ site/templates/bootstrap/header.tpl
site/templates/bootstrap/idpchoice.tpl
site/templates/bootstrap/impersonation.tpl
site/templates/bootstrap/info.tpl
site/templates/bootstrap/kerberos.tpl
site/templates/bootstrap/ldapPpGrace.tpl
site/templates/bootstrap/login.tpl
site/templates/bootstrap/logo.tpl
site/templates/bootstrap/mail.tpl
site/templates/bootstrap/menu.tpl
site/templates/bootstrap/noHistory.tpl
@ -375,7 +380,6 @@ site/templates/bootstrap/samlSpSoapLogout.tpl
site/templates/bootstrap/sessionArray.tpl
site/templates/bootstrap/simpleInfo.tpl
site/templates/bootstrap/sslform.tpl
site/templates/bootstrap/sslformChoice.tpl
site/templates/bootstrap/standardform.tpl
site/templates/bootstrap/totp2fcheck.tpl
site/templates/bootstrap/totp2fregister.tpl
@ -521,12 +525,17 @@ t/66-CDA-already-auth.t
t/66-CDA-with-REST.t
t/66-CDA-with-SOAP.t
t/66-CDA.t
t/67-CheckUser-with-Global-token.t
t/67-CheckUser-with-token.t
t/67-CheckUser.t
t/68-Impersonation-with-doubleCookies.t
t/68-Impersonation-with-merge.t
t/68-Impersonation.t
t/69-Double-cookies-for-a-Single-session.t
t/69-Double-cookies-for-Double-sessions.t
t/69-Double-cookies-Refresh-and-Logout.t
t/69-FavApps.t
t/69-HTTPS-cookie-Refresh-and-Logout.t
t/70-2F-TOTP-with-History.t
t/70-2F-TOTP.t
t/70-2F-TOTP_8.t

View File

@ -73,6 +73,7 @@ sub loadOPs {
{
$self->logger->warn(
"No OpenID Connect Provider found in configuration");
return 1;
}
# Extract JSON data
@ -97,6 +98,7 @@ sub loadRPs {
{
$self->logger->warn(
"No OpenID Connect Relying Party found in configuration");
return 1;
}
$self->oidcRPList( $self->conf->{oidcRPMetaDataOptions} );
foreach my $rp ( keys %{ $self->oidcRPList } ) {

View File

@ -1287,7 +1287,7 @@ sub getAttributeValue {
$value .= $content . $self->conf->{multiValuesSeparator}
if $content;
}
$value =~ s/$self->{conf}->{multiValuesSeparator}$//;
$value =~ s/$self->{conf}->{multiValuesSeparator}$// if $value;
# Encode UTF-8 if force_utf8 flag
$value = encode( "utf8", $value ) if $force_utf8;

View File

@ -404,7 +404,6 @@ sub setPersistentSessionInfo {
}
}
}
PE_OK;
}
@ -433,20 +432,14 @@ sub store {
$req->userData( $req->sessionInfo );
# Create second session for unsecure cookie
if ( $self->conf->{securedCookie} == 2 ) {
if ( $self->conf->{securedCookie} == 2 and !$req->refresh() ) {
my %infos = %{ $req->{sessionInfo} };
$infos{_httpSessionType} = 1;
my $session2 = $self->getApacheSession( undef, info => \%infos );
$self->logger->debug("Create second session for unsecured cookie...");
$req->{sessionInfo}->{_httpSession} = $session2->id;
}
# Compute unsecure cookie value if needed
if ( $self->conf->{securedCookie} == 3 ) {
$req->{sessionInfo}->{_httpSession} =
$self->conf->{cipher}->encryptHex( $req->{id}, "http" );
$self->logger->debug( " -> Cookie value : " . $session2->id );
}
# Fill session
@ -473,6 +466,15 @@ sub store {
return PE_APACHESESSIONERROR unless ($session);
$req->id( $session->{id} );
# Compute unsecured cookie value if needed
if ( $self->conf->{securedCookie} == 3 and !$req->refresh() ) {
$req->{sessionInfo}->{_httpSession} =
$self->conf->{cipher}->encryptHex( $req->{id}, "http" );
$self->logger->debug( " -> Compute unsecured cookie value : "
. $req->{sessionInfo}->{_httpSession} );
}
$req->refresh(0);
PE_OK;
}

View File

@ -65,6 +65,9 @@ has menuError => ( is => 'rw' );
# Frame flag (used by Run to not send Content-Security-Policy header)
has frame => ( is => 'rw' );
# Refresh flag to avoid double cookies sessions to be renewed
has refresh => ( is => 'rw' );
# Security
#
# Captcha

View File

@ -163,6 +163,7 @@ sub refresh {
'setLocalGroups',
sub {
$req->sessionInfo->{$_} = $data{$_} foreach ( keys %data );
$req->refresh(1);
return PE_OK;
},
'store',

View File

@ -11,8 +11,8 @@ use Lemonldap::NG::Portal::Main::Constants qw(
our $VERSION = '2.1.0';
extends 'Lemonldap::NG::Portal::Main::Plugin',
'Lemonldap::NG::Portal::Lib::_tokenRule';
extends qw(Lemonldap::NG::Portal::Main::Plugin
Lemonldap::NG::Portal::Lib::_tokenRule);
# INITIALIZATION
has ott => (
@ -64,17 +64,16 @@ sub check {
my $token = $req->param('token');
unless ($token) {
$self->userLogger->warn('checkUser try without token');
$msg = PE_NOTOKEN;
$token = $self->ott->createToken( { _user => $req->{_user}, } );
$msg = PE_NOTOKEN;
$token = $self->ott->createToken();
}
$token = $self->ott->getToken($token);
#unless ( $token and $token->{_user} eq $req->{_user} ) {
unless ($token) {
unless ( $self->ott->getToken($token) ) {
$self->userLogger->warn('checkUser try with expired/bad token');
$msg = PE_TOKENEXPIRED;
$token = $self->ott->createToken( { _user => $req->{_user}, } );
$msg = PE_TOKENEXPIRED;
$token = $self->ott->createToken();
}
my $params = {
PORTAL => $self->conf->{portal},
MAIN_LOGO => $self->conf->{portalMainLogo},
@ -112,7 +111,7 @@ sub check {
LOGIN => '',
TOKEN => (
$self->ottRule->( $req, {} )
? $self->ott->createToken( { _user => $req->{_user}, } )
? $self->ott->createToken()
: ''
)
}
@ -139,8 +138,6 @@ sub check {
$attrs = {};
}
else {
#$msg = 'checkUser';
$msg =
$self->{conf}->{impersonationMergeSSOgroups}
? 'checkUserMerged'
@ -222,8 +219,7 @@ sub check {
MACROS => $array_attrs->[1],
GROUPS => $array_attrs->[0],
TOKEN => (
$self->ottRule->( $req, {} )
? $self->ott->createToken( { _user => $req->{_user}, } )
$self->ottRule->( $req, {} ) ? $self->ott->createToken()
: ''
)
};
@ -282,8 +278,7 @@ sub display {
MACROS => $array_attrs->[1],
GROUPS => $array_attrs->[0],
TOKEN => (
$self->ottRule->( $req, {} )
? $self->ott->createToken( { _user => $req->{_user}, } )
$self->ottRule->( $req, {} ) ? $self->ott->createToken()
: ''
)
};

View File

@ -384,7 +384,7 @@ sub deleteSession {
my ( $self, $req, $id ) = @_;
die('id parameter is required') unless ($id);
my $session = $self->p->getApacheSession($id);
my $session = $self->p->getApacheSession($id, kind => '');
return 0 unless ($session);

View File

@ -0,0 +1,10 @@
[Unit]
Description=Cron job for Lemonldap::NG portal
After=network.target
[Service]
User=www-data
ExecStart=/usr/share/lemonldap-ng/bin/purgeCentralCache
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,9 @@
[Unit]
Description=Clean Lemonldap::NG sessions DB every 1h
[Timer]
OnCalendar=*-*-* *:07:07
Persistent=true
[Install]
WantedBy=timers.target

View File

@ -0,0 +1,146 @@
use Test::More;
use strict;
use IO::String;
BEGIN {
require 't/test-lib.pm';
}
my $res;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
authentication => 'Demo',
userDB => 'Same',
loginHistoryEnabled => 0,
brutForceProtection => 0,
portalMainLogo => 'common/logos/logo_llng_old.png',
requireToken => 0,
securedCookie => 2,
https => 0,
}
}
);
## Try to authenticate
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
count(1);
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'user', 'password' );
$query =~ s/user=/user=dwho/;
$query =~ s/password=/password=dwho/;
ok(
$res = $client->_post(
'/',
IO::String->new($query),
length => length($query),
accept => 'text/html',
),
'Auth query'
);
count(1);
my $id1 = expectCookie($res);
my $id2 = expectCookie( $res, 'lemonldaphttp' );
# Check lemonldap Cookie
ok( $id1 =~ /^\w{64}$/, " -> Get cookie : lemonldap=something" )
or explain( $res->[1], "Set-Cookie: lemonldap=$id1" );
ok( ${ $res->[1] }[3] =~ /HttpOnly=1/, " -> Cookie 'lemonldap' is HttpOnly" )
or explain( $res->[1] );
ok( ${ $res->[1] }[3] =~ /secure/, " -> Cookie 'lemonldap' is secure" )
or explain( $res->[1] );
count(3);
# Check lemonldaphttp Cookie
ok( $id2 =~ /^\w{64}$/, " -> Get cookie lemonldaphttp=something" )
or explain( $res->[1], "Set-Cookie: lemonldaphttp=$id2" );
ok(
${ $res->[1] }[5] =~ /HttpOnly=1/,
" -> Cookie 'lemonldaphttp' is HttpOnly"
) or explain( $res->[1] );
ok( ${ $res->[1] }[5] !~ /secure/, " -> Cookie 'lemonldaphttp' is NOT secure" )
or explain( $res->[1] );
count(3);
my $nbr = count_sessions();
ok( $nbr == 2, " -> Doule Cookies for two sessions found" )
or explain("Number of session(s) found = $nbr");
count(1);
expectRedirection( $res, 'http://auth.example.com/' );
# Get Menu
# ------------------------
ok(
$res = $client->_get(
'/',
cookie => "lemonldap=$id1,lemonldaphttp=$id2",
accept => 'text/html'
),
'Get Menu',
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as Dwho'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
# Refresh rights
# ------------------------
ok(
$res = $client->_get(
'/refresh',
cookie => "lemonldap=$id1,lemonldaphttp=$id2",
accept => 'text/html'
),
'Refresh query',
);
count(1);
expectRedirection( $res, 'http://auth.example.com/' );
# Get Menu
# ------------------------
ok(
$res = $client->_get(
'/',
cookie => "lemonldap=$id1,lemonldaphttp=$id2",
accept => 'text/html'
),
'Get Menu',
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as Dwho'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
# Log out request
# ------------------------
ok(
$res = $client->_get(
'/',
query => 'logout=1',
cookie => "lemonldap=$id1,lemonldaphttp=$id2",
accept => 'text/html'
),
'Get Menu',
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<div class="message message-positive alert"><span trmsg="47"></span></div>%,
'Dwho has been well disconnected'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
clean_sessions();
done_testing( count() );

View File

@ -0,0 +1,75 @@
use Test::More;
use strict;
use IO::String;
BEGIN {
require 't/test-lib.pm';
}
my $res;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
authentication => 'Demo',
userDB => 'Same',
loginHistoryEnabled => 0,
brutForceProtection => 0,
portalMainLogo => 'common/logos/logo_llng_old.png',
requireToken => 0,
securedCookie => 2,
https => 0,
}
}
);
## Try to authenticate
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
count(1);
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'user', 'password' );
$query =~ s/user=/user=dwho/;
$query =~ s/password=/password=dwho/;
ok(
$res = $client->_post(
'/',
IO::String->new($query),
length => length($query),
accept => 'text/html',
),
'Auth query'
);
count(1);
my $id1 = expectCookie($res);
my $id2 = expectCookie( $res, 'lemonldaphttp' );
# Check lemonldap Cookie
ok( $id1 =~ /^\w{64}$/, " -> Get cookie : lemonldap=something" )
or explain( $res->[1], "Set-Cookie: lemonldap=$id1" );
ok( ${ $res->[1] }[3] =~ /HttpOnly=1/, " -> Cookie 'lemonldap' is HttpOnly" )
or explain( $res->[1] );
ok( ${ $res->[1] }[3] =~ /secure/, " -> Cookie 'lemonldap' is secure" )
or explain( $res->[1] );
count(3);
# Check lemonldaphttp Cookie
ok( $id2 =~ /^\w{64}$/, " -> Get cookie lemonldaphttp=something" )
or explain( $res->[1], "Set-Cookie: lemonldaphttp=$id2" );
ok(
${ $res->[1] }[5] =~ /HttpOnly=1/,
" -> Cookie 'lemonldaphttp' is HttpOnly"
) or explain( $res->[1] );
ok( ${ $res->[1] }[5] !~ /secure/, " -> Cookie 'lemonldaphttp' is NOT secure" )
or explain( $res->[1] );
count(3);
my $nbr = count_sessions();
ok( $nbr == 2, " -> Doule Cookies for two sessions found" )
or explain("Number of session(s) found = $nbr");
count(1);
expectRedirection( $res, 'http://auth.example.com/' );
$client->logout($id1);
clean_sessions();
done_testing( count() );

View File

@ -0,0 +1,75 @@
use Test::More;
use strict;
use IO::String;
BEGIN {
require 't/test-lib.pm';
}
my $res;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
authentication => 'Demo',
userDB => 'Same',
loginHistoryEnabled => 0,
brutForceProtection => 0,
portalMainLogo => 'common/logos/logo_llng_old.png',
requireToken => 0,
securedCookie => 3,
https => 0,
}
}
);
## Try to authenticate
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
count(1);
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'user', 'password' );
$query =~ s/user=/user=dwho/;
$query =~ s/password=/password=dwho/;
ok(
$res = $client->_post(
'/',
IO::String->new($query),
length => length($query),
accept => 'text/html',
),
'Auth query'
);
count(1);
my $id1 = expectCookie($res);
my $id2 = expectCookie( $res, 'lemonldaphttp' );
# Check lemonldap Cookie
ok( $id1 =~ /^\w{64}$/, " -> Get cookie : lemonldap=something" )
or explain( $res->[1], "Set-Cookie: lemonldap=$id1" );
ok( ${ $res->[1] }[3] =~ /HttpOnly=1/, " -> Cookie 'lemonldap' is HttpOnly" )
or explain( $res->[1] );
ok( ${ $res->[1] }[3] =~ /secure/, " -> Cookie 'lemonldap' is secure" )
or explain( $res->[1] );
count(3);
# Check lemonldaphttp Cookie
ok( $id2 =~ /^\w{64}$/, " -> Get cookie lemonldaphttp=something" )
or explain( $res->[1], "Set-Cookie: lemonldaphttp=$id2" );
ok(
${ $res->[1] }[5] =~ /HttpOnly=1/,
" -> Cookie 'lemonldaphttp' is HttpOnly"
) or explain( $res->[1] );
ok( ${ $res->[1] }[5] !~ /secure/, " -> Cookie 'lemonldaphttp' is NOT secure" )
or explain( $res->[1] );
count(3);
my $nbr = count_sessions();
ok( $nbr == 1, " -> Doule Cookies for a single session" )
or explain("Number of session(s) found = $nbr");
count(1);
expectRedirection( $res, 'http://auth.example.com/' );
$client->logout($id1);
clean_sessions();
done_testing( count() );

View File

@ -0,0 +1,134 @@
use Test::More;
use strict;
use IO::String;
BEGIN {
require 't/test-lib.pm';
}
my $res;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
authentication => 'Demo',
userDB => 'Same',
loginHistoryEnabled => 0,
brutForceProtection => 0,
portalMainLogo => 'common/logos/logo_llng_old.png',
requireToken => 0,
securedCookie => 1,
https => 0,
}
}
);
## Try to authenticate
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
count(1);
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'user', 'password' );
$query =~ s/user=/user=dwho/;
$query =~ s/password=/password=dwho/;
ok(
$res = $client->_post(
'/',
IO::String->new($query),
length => length($query),
accept => 'text/html',
),
'Auth query'
);
count(1);
my $id = expectCookie($res);
# Check lemonldap Cookie
ok( $id =~ /^\w{64}$/, " -> Get cookie : lemonldap=something" )
or explain( $res->[1], "Set-Cookie: lemonldap=$id" );
ok( ${ $res->[1] }[3] =~ /HttpOnly=1/, " -> Cookie 'lemonldap' is HttpOnly" )
or explain( $res->[1] );
ok( ${ $res->[1] }[3] =~ /secure/, " -> Cookie 'lemonldap' is secure" )
or explain( $res->[1] );
count(3);
my $nbr = count_sessions();
ok( $nbr == 1, " -> HTTPS Cookie for one session found" )
or explain("Number of session(s) found = $nbr");
count(1);
expectRedirection( $res, 'http://auth.example.com/' );
# Get Menu
# ------------------------
ok(
$res = $client->_get(
'/',
cookie => "lemonldap=$id",
accept => 'text/html'
),
'Get Menu',
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as Dwho'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
# Refresh rights
# ------------------------
ok(
$res = $client->_get(
'/refresh',
cookie => "lemonldap=$id",
accept => 'text/html'
),
'Refresh query',
);
count(1);
expectRedirection( $res, 'http://auth.example.com/' );
# Get Menu
# ------------------------
ok(
$res = $client->_get(
'/',
cookie => "lemonldap=$id",
accept => 'text/html'
),
'Get Menu',
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as Dwho'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
# Log out request
# ------------------------
ok(
$res = $client->_get(
'/',
query => 'logout=1',
cookie => "lemonldap=$id",
accept => 'text/html'
),
'Get Menu',
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<div class="message message-positive alert"><span trmsg="47"></span></div>%,
'Dwho has been well disconnected'
) or print STDERR Dumper( $res->[2]->[0] );
count(1);
clean_sessions();
done_testing( count() );

View File

@ -123,6 +123,18 @@ sub clean_sessions {
$cache->clear;
}
sub count_sessions {
my $dir = shift;
$dir ||= 't/sessions';
my $nbr = 0;
opendir D, $dir or die $!;
foreach ( grep { /^\w{64}$/ } readdir(D) ) {
$nbr++;
}
$nbr;
}
sub getCache {
require Cache::FileCache;
return Cache::FileCache->new( {