From f917a9cfecdad67b7a1a2b7ab01ca5777ea63434 Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Sat, 11 May 2019 22:52:07 +0200 Subject: [PATCH 01/19] Improve unit test for doubleCookie --- lemonldap-ng-handler/t/63-Lemonldap-NG-Handler-PSGI-Try.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lemonldap-ng-handler/t/63-Lemonldap-NG-Handler-PSGI-Try.t b/lemonldap-ng-handler/t/63-Lemonldap-NG-Handler-PSGI-Try.t index 51b117ce2..0240674a5 100644 --- a/lemonldap-ng-handler/t/63-Lemonldap-NG-Handler-PSGI-Try.t +++ b/lemonldap-ng-handler/t/63-Lemonldap-NG-Handler-PSGI-Try.t @@ -18,8 +18,8 @@ ok( localSessionStorage => '', logLevel => 'warn', cookieName => 'lemonldap', - securedCookie => 0, - https => 0, + securedCookie => 2, + https => 1, userLogger => 'Lemonldap::NG::Common::Logger::Null', } ), From 8737fc08087d3fcedd6ef008d81b7e0d43e61923 Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Sat, 11 May 2019 22:57:52 +0200 Subject: [PATCH 02/19] Impersonation with doubleCookie & Append unit test (#1746) --- .../NG/Portal/Plugins/Impersonation.pm | 4 +- .../t/68-Impersonation-with-doubleCookies.t | 309 ++++++++++++++++++ 2 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm index c261fbe27..c807485ef 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm @@ -55,7 +55,6 @@ sub init { sub run { my ( $self, $req ) = @_; - my $savedHttpSession = $req->{sessionInfo}->{_httpSession} //= ''; my $spoofId = $req->param('spoofId') || $req->{user}; $self->logger->debug("No impersonation required") if ( $spoofId eq $req->{user} ); @@ -142,8 +141,7 @@ sub run { $req->steps( [ $self->p->validSession, @{ $self->p->endAuth } ] ); # Restore _httpSession for double Cookies - $req->{sessionInfo}->{_httpSession} = $savedHttpSession - if $savedHttpSession; + $req->{sessionInfo}->{_httpSession} = $req->{sessionInfo}->{real__httpSession} if $req->{sessionInfo}->{real__httpSession}; return $statut; } diff --git a/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t b/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t new file mode 100644 index 000000000..65a3b83db --- /dev/null +++ b/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t @@ -0,0 +1,309 @@ +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, + checkUser => 1, + impersonationRule => '$uid ne "msmith"', + impersonationIdRule => '$uid ne "msmith"', + impersonationPrefix => 'testPrefix_', + securedCookie => 2, + https => 1, + checkUserDisplayPersistentInfo => 0, + checkUserDisplayEmptyValues => 0, + impersonationMergeSSOgroups => 0, + macros => { + test_impersonation => '"$testPrefix__user/$_user"', + _whatToTrace => + '$_auth eq "SAML" ? "$_user@$_idpConfKey" : $_user', + }, + } + } +); + +## Try to impersonate with a bad spoofed user +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +my ( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=rtyler/; +$query =~ s/password=/password=rtyler/; +$query =~ s/spoofId=/spoofId=dwho*/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +ok( $res->[2]->[0] =~ m%%, ' PE40 found' ) + or explain( $res->[2]->[0], "PE40 - Bad formed user" ); +count(2); + +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +## Try to impersonate with a forbidden identity +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=rtyler/; +$query =~ s/password=/password=rtyler/; +$query =~ s/spoofId=/spoofId=msmith/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +ok( + $res->[2]->[0] =~ +m%
%, + ' PE5 found' +) or explain( $res->[2]->[0], "PE5 - Forbidden identity" ); +count(2); + +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +## An unauthorized user try to impersonate +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=msmith/; +$query =~ s/password=/password=msmith/; +$query =~ s/spoofId=/spoofId=rtyler/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +ok( + $res->[2]->[0] =~ +m%
%, + ' PE93 found' +) or explain( $res->[2]->[0], "PE93 - Impersonation service not allowed" ); +count(2); + +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +## An unauthorized user to impersonate tries to authenticate +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=msmith/; +$query =~ s/password=/password=msmith/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +count(1); + +my $id = expectCookie($res); +expectRedirection( $res, 'http://auth.example.com/' ); + +# CheckUser form +# ------------------------ +ok( + $res = $client->_get( + '/checkuser', + cookie => "lemonldap=$id", + accept => 'text/html' + ), + 'CheckUser form', +); +count(1); +( $host, $url, $query ) = + expectForm( $res, undef, '/checkuser', 'user', 'url' ); +ok( $res->[2]->[0] =~ m%%, 'Found trspan="checkUser"' ) + or explain( $res->[2]->[0], 'trspan="checkUser"' ); +count(1); + +ok( + $res = $client->_post( + '/checkuser', + IO::String->new($query), + cookie => "lemonldap=$id", + length => length($query), + accept => 'text/html', + ), + 'POST checkuser' +); +count(1); + +ok( $res->[2]->[0] =~ m%test_impersonation%, + 'Found macro test_impersonation' ) + or explain( $res->[2]->[0], 'test_impersonation' ); +ok( $res->[2]->[0] =~ m%msmith/msmith%, + 'Found msmith/msmith' ) + or explain( $res->[2]->[0], 'Found msmith/msmith' ); +count(2); + +$client->logout($id); + +## Try to authenticate +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=rtyler/; +$query =~ s/password=/password=rtyler/; +$query =~ s/spoofId=/spoofId=dwho/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +count(1); + +$id = expectCookie($res); +expectRedirection( $res, 'http://auth.example.com/' ); + +# CheckUser form +# ------------------------ +ok( + $res = $client->_get( + '/checkuser', + cookie => "lemonldap=$id", + accept => 'text/html' + ), + 'CheckUser form', +); +count(1); +( $host, $url, $query ) = + expectForm( $res, undef, '/checkuser', 'user', 'url' ); +ok( $res->[2]->[0] =~ m%%, 'Found trspan="checkUser"' ) + or explain( $res->[2]->[0], 'trspan="checkUser"' ); +count(1); + +$query =~ s/url=/url=test1.example.com/; + +ok( + $res = $client->_post( + '/checkuser', + IO::String->new($query), + cookie => "lemonldap=$id", + length => length($query), + accept => 'text/html', + ), + 'POST checkuser' +); +count(1); + +( $host, $url, $query ) = + expectForm( $res, undef, '/checkuser', 'user', 'url' ); +ok( $res->[2]->[0] =~ m%%, 'Found trspan="checkUser"' ) + or explain( $res->[2]->[0], 'trspan="checkUser"' ); +ok( + $res->[2]->[0] =~ +m%
%, + 'Found trspan="allowed"' +) or explain( $res->[2]->[0], 'trspan="allowed"' ); +ok( $res->[2]->[0] =~ m%%, 'Found trspan="headers"' ) + or explain( $res->[2]->[0], 'trspan="headers"' ); + +ok( $res->[2]->[0] !~ m%%, + 'trspan="groups_sso" NOT found' ) + or explain( $res->[2]->[0], 'trspan="groups_sso"' ); + +ok( $res->[2]->[0] =~ m%%, 'Found trspan="macros"' ) + or explain( $res->[2]->[0], 'trspan="macros"' ); +ok( $res->[2]->[0] =~ m%%, + 'Found trspan="attributes"' ) + or explain( $res->[2]->[0], 'trspan="attributes"' ); +ok( $res->[2]->[0] =~ m%_userDB%, 'Found _userDB' ) + or explain( $res->[2]->[0], '_userDB' ); +ok( $res->[2]->[0] =~ m%Auth-User%, + 'Found Auth-User' ) + or explain( $res->[2]->[0], 'Header Key: Auth-User' ); +ok( $res->[2]->[0] =~ m%dwho%, 'Found dwho' ) + or explain( $res->[2]->[0], 'Header Value: dwho' ); + +ok( $res->[2]->[0] =~ m%_whatToTrace%, + 'Found _whatToTrace' ) + or explain( $res->[2]->[0], 'Macro Key _whatToTrace' ); +ok( $res->[2]->[0] =~ m%testPrefix_groups%, + 'Found testPrefix_groups' ) + or explain( $res->[2]->[0], 'testPrefix_groups' ); +ok( $res->[2]->[0] =~ m%su%, 'Found su' ) + or explain( $res->[2]->[0], 'su' ); +ok( $res->[2]->[0] =~ m%testPrefix_uid%, + 'Found testPrefix_uid' ) + or explain( $res->[2]->[0], 'testPrefix_groups' ); +ok( $res->[2]->[0] =~ m%rtyler%, 'Found rtyler' ) + or explain( $res->[2]->[0], 'su' ); +ok( $res->[2]->[0] =~ m%test_impersonation%, + 'Found macro test_impersonation' ) + or explain( $res->[2]->[0], 'test_impersonation' ); +ok( $res->[2]->[0] =~ m%rtyler/dwho%, + 'Found rtyler/dwo' ) + or explain( $res->[2]->[0], 'Found rtyler/dwo' ); +count(16); + +my @attributes = map /(.+)?<\/td>/g, $res->[2]->[0]; +ok( scalar @attributes == 62, 'Found 61 attributes' ) + or print STDERR ( @attributes < 62 ) + ? "Missing attributes -> " . scalar @attributes + : "Too much attributes -> " . scalar @attributes; +ok( $attributes[0] eq '_auth', '_auth' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[1] eq 'Demo', 'Demo' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[2] eq '_httpSession', '_httpSession' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[28] eq 'uid', 'uid' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[30] eq 'testPrefix__auth', 'testPrefix__auth' ) + or print STDERR Dumper( \@attributes ); +ok( $attributes[32] eq 'testPrefix__httpSession', 'testPrefix__httpSession' ) + or print STDERR Dumper( \@attributes ); +ok( $attributes[60] eq 'testPrefix_uid', 'testPrefix_uid' ) + or print STDERR Dumper( \@attributes ); +ok( $attributes[61] eq 'rtyler', 'rtyler' ) + or print STDERR Dumper( \@attributes ); +count(9); + +$client->logout($id); +clean_sessions(); + +done_testing( count() ); From a93caace4b139ae5539f4f572abc69e6f27300fc Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Sat, 11 May 2019 23:01:52 +0200 Subject: [PATCH 03/19] Improve unit test (#1746) --- lemonldap-ng-portal/t/68-Impersonation.t | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lemonldap-ng-portal/t/68-Impersonation.t b/lemonldap-ng-portal/t/68-Impersonation.t index 8d0e09b30..0af1bd44c 100644 --- a/lemonldap-ng-portal/t/68-Impersonation.t +++ b/lemonldap-ng-portal/t/68-Impersonation.t @@ -21,6 +21,8 @@ my $client = LLNG::Manager::Test->new( { impersonationRule => '$uid ne "msmith"', impersonationIdRule => '$uid ne "msmith"', impersonationPrefix => 'testPrefix_', + securedCookie => 1, + https => 0, checkUserDisplayPersistentInfo => 0, checkUserDisplayEmptyValues => 0, impersonationMergeSSOgroups => 0, From 9a71709f4445e295f6fdbded07a3aedc0de88c9b Mon Sep 17 00:00:00 2001 From: Xavier Date: Sat, 11 May 2019 23:03:48 +0200 Subject: [PATCH 04/19] Tidy --- .../lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm | 4 +++- lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm index c807485ef..b3316f5b5 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm @@ -141,7 +141,9 @@ sub run { $req->steps( [ $self->p->validSession, @{ $self->p->endAuth } ] ); # Restore _httpSession for double Cookies - $req->{sessionInfo}->{_httpSession} = $req->{sessionInfo}->{real__httpSession} if $req->{sessionInfo}->{real__httpSession}; + $req->{sessionInfo}->{_httpSession} = + $req->{sessionInfo}->{real__httpSession} + if $req->{sessionInfo}->{real__httpSession}; return $statut; } diff --git a/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t b/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t index 65a3b83db..262518c61 100644 --- a/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t +++ b/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t @@ -291,8 +291,9 @@ ok( scalar @attributes == 62, 'Found 61 attributes' ) : "Too much attributes -> " . scalar @attributes; ok( $attributes[0] eq '_auth', '_auth' ) or print STDERR Dumper( \@attributes ); ok( $attributes[1] eq 'Demo', 'Demo' ) or print STDERR Dumper( \@attributes ); -ok( $attributes[2] eq '_httpSession', '_httpSession' ) or print STDERR Dumper( \@attributes ); -ok( $attributes[28] eq 'uid', 'uid' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[2] eq '_httpSession', '_httpSession' ) + or print STDERR Dumper( \@attributes ); +ok( $attributes[28] eq 'uid', 'uid' ) or print STDERR Dumper( \@attributes ); ok( $attributes[30] eq 'testPrefix__auth', 'testPrefix__auth' ) or print STDERR Dumper( \@attributes ); ok( $attributes[32] eq 'testPrefix__httpSession', 'testPrefix__httpSession' ) From e8b4e0c52c46e3036fdbe68fc5f8ef9a62776029 Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Sat, 11 May 2019 23:21:41 +0200 Subject: [PATCH 05/19] Update manifest --- lemonldap-ng-portal/MANIFEST | 1 + 1 file changed, 1 insertion(+) diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index 990e3bb9c..541cb12cc 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -517,6 +517,7 @@ t/66-CDA-with-SOAP.t t/66-CDA.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/70-2F-TOTP-with-History.t From 807959dd40078373bbc29d20c424fd3dcac18f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20OUDOT?= Date: Sun, 12 May 2019 16:16:42 +0200 Subject: [PATCH 06/19] Include 1.9.19 in changelog --- changelog | 14 ++++++++++++++ debian/changelog | 7 +++++++ rpm/lemonldap-ng.spec | 3 +++ 3 files changed, 24 insertions(+) diff --git a/changelog b/changelog index 6be91103e..6936c87de 100644 --- a/changelog +++ b/changelog @@ -242,6 +242,20 @@ lemonldap-ng (2.0.0~alpha2) testing; urgency=low lemonldap-ng (2.0.0~alpha1) testing; urgency=low +lemonldap-ng (1.9.19) oldstable; urgency=high + + * Bugs: + * #1509: InactivityTimeout for applications don't work + * #1520: lemonldap-ng-cli adds a new item when deleting an item that does not exist. + * #1567: Captcha session id is too weak + * #1580: Error when saving in manager (mongoDB as ConfigurationBackend) + * #1662: id_token validity not correctly evaluated + * #1744: [Security: low] register_token used for account creation can be used as a valid session identifier + + * Improvements: + * #1516: All IDP conf not usable if only one IDP misconfigured + * #1519: Cross domain authentication, ajax request and same origin policy + lemonldap-ng (1.9.18) stable; urgency=high * #1479: App Category order - Cannot save diff --git a/debian/changelog b/debian/changelog index 2a95b1a78..41b8f3c04 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +lemonldap-ng (1.9.19-1) unstable; urgency=medium + + * New release. See changes on our website: + https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng + + -- Clement OUDOT Sun, 12 May 2019 12:00:00 +0100 + lemonldap-ng (2.0.3-1) unstable; urgency=medium * New release. See changes on our website: diff --git a/rpm/lemonldap-ng.spec b/rpm/lemonldap-ng.spec index e3cd964e4..a08f47b5b 100644 --- a/rpm/lemonldap-ng.spec +++ b/rpm/lemonldap-ng.spec @@ -660,6 +660,9 @@ fi # Changelog #============================================================================== %changelog +* Sun May 12 2019 Clement Oudot - 1.9.19-1 +- Update to 1.9.19 + * Thu Apr 11 2019 Clement Oudot - 2.0.3-1 - Update to 2.0.3 From 332fb4f9da6a7a009660d944b0ca5f4e97ca5a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20OUDOT?= Date: Sun, 12 May 2019 16:22:50 +0200 Subject: [PATCH 07/19] Update version in module dependencies --- lemonldap-ng-common/META.json | 6 +++--- lemonldap-ng-common/META.yml | 2 +- lemonldap-ng-handler/META.json | 8 ++++---- lemonldap-ng-handler/META.yml | 4 ++-- lemonldap-ng-handler/Makefile.PL | 2 +- lemonldap-ng-manager/META.json | 10 +++++----- lemonldap-ng-manager/META.yml | 6 +++--- lemonldap-ng-manager/Makefile.PL | 4 ++-- lemonldap-ng-portal/META.json | 8 ++++---- lemonldap-ng-portal/META.yml | 4 ++-- lemonldap-ng-portal/Makefile.PL | 2 +- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/lemonldap-ng-common/META.json b/lemonldap-ng-common/META.json index bd42a8553..193030fa6 100644 --- a/lemonldap-ng-common/META.json +++ b/lemonldap-ng-common/META.json @@ -4,13 +4,13 @@ "Xavier Guimard , Clément Oudot " ], "dynamic_config" : 1, - "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", + "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010", "license" : [ "open_source" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", - "version" : 2 + "version" : "2" }, "name" : "Lemonldap-NG-Common", "no_index" : { @@ -72,5 +72,5 @@ "x_MailingList" : "mailto:lemonldap-ng-dev@ow2.org" }, "version" : "v2.0.4", - "x_serialization_backend" : "JSON::PP version 2.97001" + "x_serialization_backend" : "JSON::PP version 2.27400_02" } diff --git a/lemonldap-ng-common/META.yml b/lemonldap-ng-common/META.yml index 67371d8d9..f58d6eccd 100644 --- a/lemonldap-ng-common/META.yml +++ b/lemonldap-ng-common/META.yml @@ -9,7 +9,7 @@ build_requires: configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 -generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' +generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010' license: open_source meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html diff --git a/lemonldap-ng-handler/META.json b/lemonldap-ng-handler/META.json index 49a9779df..808e97c07 100644 --- a/lemonldap-ng-handler/META.json +++ b/lemonldap-ng-handler/META.json @@ -4,13 +4,13 @@ "Xavier Guimard , Clément Oudot " ], "dynamic_config" : 1, - "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", + "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010", "license" : [ "open_source" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", - "version" : 2 + "version" : "2" }, "name" : "Lemonldap-NG-Handler", "no_index" : { @@ -43,7 +43,7 @@ }, "requires" : { "LWP::UserAgent" : "0", - "Lemonldap::NG::Common" : "v2.0.3", + "Lemonldap::NG::Common" : "v2.0.4", "Mouse" : "0", "URI" : "0" } @@ -59,5 +59,5 @@ "x_MailingList" : "mailto:lemonldap-ng-dev@ow2.org" }, "version" : "v2.0.4", - "x_serialization_backend" : "JSON::PP version 2.97001" + "x_serialization_backend" : "JSON::PP version 2.27400_02" } diff --git a/lemonldap-ng-handler/META.yml b/lemonldap-ng-handler/META.yml index 970b5b287..d36ae2e91 100644 --- a/lemonldap-ng-handler/META.yml +++ b/lemonldap-ng-handler/META.yml @@ -11,7 +11,7 @@ build_requires: configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 -generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' +generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010' license: open_source meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -28,7 +28,7 @@ recommends: SOAP::Lite: '0' requires: LWP::UserAgent: '0' - Lemonldap::NG::Common: v2.0.3 + Lemonldap::NG::Common: v2.0.4 Mouse: '0' URI: '0' resources: diff --git a/lemonldap-ng-handler/Makefile.PL b/lemonldap-ng-handler/Makefile.PL index 76b6cca3e..55119e43d 100644 --- a/lemonldap-ng-handler/Makefile.PL +++ b/lemonldap-ng-handler/Makefile.PL @@ -39,7 +39,7 @@ WriteMakefile( }, }, PREREQ_PM => { - 'Lemonldap::NG::Common' => '2.0.3', + 'Lemonldap::NG::Common' => '2.0.4', 'LWP::UserAgent' => 0, 'Mouse' => 0, 'URI' => 0, diff --git a/lemonldap-ng-manager/META.json b/lemonldap-ng-manager/META.json index 912a479b6..a962fa4d4 100644 --- a/lemonldap-ng-manager/META.json +++ b/lemonldap-ng-manager/META.json @@ -4,13 +4,13 @@ "Xavier Guimard , Clément Oudot " ], "dynamic_config" : 1, - "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", + "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010", "license" : [ "open_source" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", - "version" : 2 + "version" : "2" }, "name" : "Lemonldap-NG-Manager", "no_index" : { @@ -40,8 +40,8 @@ "Convert::PEM" : "0", "Crypt::OpenSSL::RSA" : "0", "LWP::UserAgent" : "0", - "Lemonldap::NG::Common" : "v2.0.3", - "Lemonldap::NG::Handler" : "v2.0.3" + "Lemonldap::NG::Common" : "v2.0.4", + "Lemonldap::NG::Handler" : "v2.0.4" } } }, @@ -55,5 +55,5 @@ "x_MailingList" : "mailto:lemonldap-ng-dev@ow2.org" }, "version" : "v2.0.4", - "x_serialization_backend" : "JSON::PP version 2.97001" + "x_serialization_backend" : "JSON::PP version 2.27400_02" } diff --git a/lemonldap-ng-manager/META.yml b/lemonldap-ng-manager/META.yml index a99ebe5c0..9ff57b806 100644 --- a/lemonldap-ng-manager/META.yml +++ b/lemonldap-ng-manager/META.yml @@ -9,7 +9,7 @@ build_requires: configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 -generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' +generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010' license: open_source meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -25,8 +25,8 @@ requires: Convert::PEM: '0' Crypt::OpenSSL::RSA: '0' LWP::UserAgent: '0' - Lemonldap::NG::Common: v2.0.3 - Lemonldap::NG::Handler: v2.0.3 + Lemonldap::NG::Common: v2.0.4 + Lemonldap::NG::Handler: v2.0.4 resources: MailingList: mailto:lemonldap-ng-dev@ow2.org X_twitter: https://twitter.com/lemonldapng diff --git a/lemonldap-ng-manager/Makefile.PL b/lemonldap-ng-manager/Makefile.PL index 8f03f4f08..d746292ca 100644 --- a/lemonldap-ng-manager/Makefile.PL +++ b/lemonldap-ng-manager/Makefile.PL @@ -35,8 +35,8 @@ WriteMakefile( PREREQ_PM => { 'Convert::PEM' => 0, 'Crypt::OpenSSL::RSA' => 0, - 'Lemonldap::NG::Common' => '2.0.3', - 'Lemonldap::NG::Handler' => '2.0.3', + 'Lemonldap::NG::Common' => '2.0.4', + 'Lemonldap::NG::Handler' => '2.0.4', 'LWP::UserAgent' => 0, }, # e.g., Module::Name => 1.1 ( diff --git a/lemonldap-ng-portal/META.json b/lemonldap-ng-portal/META.json index 11beab223..c85aa5d50 100644 --- a/lemonldap-ng-portal/META.json +++ b/lemonldap-ng-portal/META.json @@ -4,13 +4,13 @@ "Xavier Guimard , Clément Oudot " ], "dynamic_config" : 1, - "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", + "generated_by" : "ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010", "license" : [ "open_source" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", - "version" : 2 + "version" : "2" }, "name" : "Lemonldap-NG-Portal", "no_index" : { @@ -63,7 +63,7 @@ }, "requires" : { "Clone" : "0", - "Lemonldap::NG::Handler" : "v2.0.3", + "Lemonldap::NG::Handler" : "v2.0.4", "Regexp::Assemble" : "0" } } @@ -78,5 +78,5 @@ "x_MailingList" : "mailto:lemonldap-ng-dev@ow2.org" }, "version" : "v2.0.4", - "x_serialization_backend" : "JSON::PP version 2.97001" + "x_serialization_backend" : "JSON::PP version 2.27400_02" } diff --git a/lemonldap-ng-portal/META.yml b/lemonldap-ng-portal/META.yml index a6d75ad47..854ab4517 100644 --- a/lemonldap-ng-portal/META.yml +++ b/lemonldap-ng-portal/META.yml @@ -14,7 +14,7 @@ build_requires: configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 -generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' +generated_by: 'ExtUtils::MakeMaker version 7.24, CPAN::Meta::Converter version 2.150010' license: open_source meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -48,7 +48,7 @@ recommends: Web::ID: '0' requires: Clone: '0' - Lemonldap::NG::Handler: v2.0.3 + Lemonldap::NG::Handler: v2.0.4 Regexp::Assemble: '0' resources: MailingList: mailto:lemonldap-ng-dev@ow2.org diff --git a/lemonldap-ng-portal/Makefile.PL b/lemonldap-ng-portal/Makefile.PL index 15c5350f6..f087cda7b 100644 --- a/lemonldap-ng-portal/Makefile.PL +++ b/lemonldap-ng-portal/Makefile.PL @@ -59,7 +59,7 @@ WriteMakefile( }, PREREQ_PM => { 'Clone' => 0, - 'Lemonldap::NG::Handler' => '2.0.3', + 'Lemonldap::NG::Handler' => '2.0.4', 'Regexp::Assemble' => 0, }, ( From 21dc5bff73e3ea88c645b92403289030e2df4598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20OUDOT?= Date: Sun, 12 May 2019 16:28:20 +0200 Subject: [PATCH 08/19] Update version in changelog, Debian and RPM --- changelog | 37 +++++++++++++++++++++++++++++++++++++ debian/changelog | 7 +++++++ rpm/lemonldap-ng.spec | 5 ++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/changelog b/changelog index 6936c87de..58dcf2d56 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,40 @@ +lemonldap-ng (2.0.4) bionic; urgency=medium + + * Bugs: + * #1684: UI manager: boolean values do not appears in configuration forms with Yaml config format + * #1709: ViewDiff template not displayed + * #1710: Configuration keys not displayed in Viewer + * #1716: [Security:minor] Update jQuery + * #1720: Duplicate session opening when using multiple Kerberos instances in Combination + * #1724: CAS 1.0 /validate endpoint does not return username + * #1726: Deb package: missing dependency IO::String + * #1733: Invalid default crontab in RPM + * #1736: Configuration version in Manager is different from software version + * #1738: Error not well catched with Ext2F + * #1741: Deleted category is not detected as a change when saving conf. + * #1742: [Security: high] Setting tokenUseGlobalStorage allows unauthenticated users to access the portal (and applications without rules) + * #1743: [Security: low] register_token used for account creation can be used as a valid session identifier + * #1746: Impersonation does not work with double cookies authentication + + * New features: + * #1146: Allow Handler to read OAuth2 access token instead of browser cookie + * #1722: [Security: improvement] PKCE to secure OIDC Authorization Code flow + + * Improvements: + * #1703: Fix faulty headers on a null value + * #1711: Return Session ID when authentication is done via REST + * #1712: Display idpChoice cancel button only if AuthChoice is enabled + * #1713: CAS : Allow per application CAS login override + * #1714: Check logLevel value + * #1725: Allow unauthenticated clients on OIDC token endpoint + * #1728: Improve redirect page + * #1729: Display error if SAML service is enabled without private and public keys signature + * #1730: Sort real and spoofed attributes in CheckUser and Session explorer + * #1735: Highlight valid SSO sessions in sessions explorer + * #1739: Improve log in Grant Session plugin + + -- Clément Sun, 12 May 2019 16:17:01 +0200 + lemonldap-ng (2.0.3) bionic; urgency=medium * Bugs: diff --git a/debian/changelog b/debian/changelog index 41b8f3c04..3aa386d50 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +lemonldap-ng (2.0.4-1) unstable; urgency=medium + + * New release. See changes on our website: + https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng + + -- Clement OUDOT Sun, 12 May 2019 16:00:00 +0100 + lemonldap-ng (1.9.19-1) unstable; urgency=medium * New release. See changes on our website: diff --git a/rpm/lemonldap-ng.spec b/rpm/lemonldap-ng.spec index a08f47b5b..32856b3f2 100644 --- a/rpm/lemonldap-ng.spec +++ b/rpm/lemonldap-ng.spec @@ -49,7 +49,7 @@ # Main package #============================================================================== Name: lemonldap-ng -Version: 2.0.3 +Version: 2.0.4 Release: %{?pre_release:0.}1%{?pre_release:.%{pre_release}}%{?dist} Summary: LemonLDAP-NG WebSSO License: GPLv2+ @@ -660,6 +660,9 @@ fi # Changelog #============================================================================== %changelog +* Sun May 12 2019 Clement Oudot - 2.0.4-1 +- Update to 2.0.4 + * Sun May 12 2019 Clement Oudot - 1.9.19-1 - Update to 1.9.19 From 12fec2e41a72a00acd3ba888ea6db0fb7dcde062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20OUDOT?= Date: Sun, 12 May 2019 16:33:56 +0200 Subject: [PATCH 09/19] Update documentation --- .../documentation/current/applications.html | 71 ++++---- .../current/applications/googleapps.html | 13 +- .../current/applications/guacamole.html | 152 ++++++++++++++++++ .../current/applications/img/icons.png | 4 +- .../current/applications/img/loader.gif | 4 +- .../current/applications/zimbra.html | 2 +- doc/pages/documentation/current/authcas.html | 2 +- .../current/authcombination.html | 2 +- doc/pages/documentation/current/authgpg.html | 2 +- .../current/authopenidconnect.html | 2 +- doc/pages/documentation/current/authrest.html | 2 +- doc/pages/documentation/current/authsaml.html | 2 +- doc/pages/documentation/current/authssl.html | 12 +- .../current/browseablesessionbackend.html | 31 ++-- .../documentation/current/contribute.html | 2 +- ...view.5ca2e2d7241bbcec7d492df10866fdd3.jpeg | Bin 0 -> 9158 bytes .../current/documentation/oauth2_handler.png | Bin 0 -> 52860 bytes doc/pages/documentation/current/dos | 4 +- doc/pages/documentation/current/exploit | 4 +- .../documentation/current/external2f.html | 40 ++++- .../documentation/current/grantsession.html | 87 ++++++++++ .../documentation/current/handlerarch.html | 10 +- .../current/handlerauthbasic.html | 2 +- doc/pages/documentation/current/idpcas.html | 30 ++-- .../current/idpopenidconnect.html | 24 ++- .../documentation/current/impersonation.html | 12 +- doc/pages/documentation/current/mitm | 4 +- .../documentation/current/oauth2handler.html | 97 +++++++++++ .../documentation/current/parameterlist.html | 2 +- .../documentation/current/performances.html | 67 +++++--- .../documentation/current/plugincustom.html | 36 ++++- .../documentation/current/portalcustom.html | 18 +-- .../documentation/current/portalmenu.html | 2 +- .../documentation/current/portalservers.html | 14 +- .../documentation/current/resetpassword.html | 10 +- .../documentation/current/restservices.html | 135 +++++++++++++++- doc/pages/documentation/current/security.html | 45 +++--- .../current/selfmadeapplication.html | 2 +- doc/pages/documentation/current/sessions.html | 6 +- doc/pages/documentation/current/smtp.html | 12 +- doc/pages/documentation/current/start.html | 57 ++++--- doc/pages/documentation/current/stayconnected | 4 +- 42 files changed, 803 insertions(+), 224 deletions(-) create mode 100644 doc/pages/documentation/current/applications/guacamole.html create mode 100644 doc/pages/documentation/current/documentation/oauth-retina-preview.5ca2e2d7241bbcec7d492df10866fdd3.jpeg create mode 100644 doc/pages/documentation/current/documentation/oauth2_handler.png create mode 100644 doc/pages/documentation/current/grantsession.html create mode 100644 doc/pages/documentation/current/oauth2handler.html diff --git a/doc/pages/documentation/current/applications.html b/doc/pages/documentation/current/applications.html index 67e282c87..b49d8adc4 100644 --- a/doc/pages/documentation/current/applications.html +++ b/doc/pages/documentation/current/applications.html @@ -137,70 +137,73 @@ If none of above methods is available, you can try: GRR ✔ - Liferay ✔ + Apache Guacamole ✔ ✔ ✔ - LimeSurvey LimeSurvey ✔ + Liferay ✔ - Mediawiki ✔ + LimeSurvey LimeSurvey ✔ - NextCloud ✔ + Mediawiki ✔ - HTTP headers Specific Handler CAS SAML OpenID Connect + NextCloud ✔ - OBM ✔ - - - Office 365 ✔ - - - phpLDAPAdmin ✔ - - - Roundcube ✔ - - - SalesForce ✔ - - - SAP SAP ✔ ✔ - - - simpleSAMLphp ✔ - - HTTP headers Specific Handler CAS SAML OpenID Connect + + OBM ✔ + + + Office 365 ✔ + + + phpLDAPAdmin ✔ + + + Roundcube ✔ + + + SalesForce ✔ + + + SAP SAP ✔ ✔ + + + simpleSAMLphp ✔ + - Spring ✔ + HTTP headers Specific Handler CAS SAML OpenID Connect - Symfony ✔ + Spring ✔ - Sympa ✔ + Symfony ✔ - Tomcat ✔ + Sympa ✔ - Wordpress ✔ + Tomcat ✔ - XWiki ✔ + Wordpress ✔ - Zimbra ✔ + XWiki ✔ + Zimbra ✔ + + HTTP headers Specific Handler CAS SAML OpenID Connect - + diff --git a/doc/pages/documentation/current/applications/googleapps.html b/doc/pages/documentation/current/applications/googleapps.html index 7e62cbbf2..da6454d5f 100644 --- a/doc/pages/documentation/current/applications/googleapps.html +++ b/doc/pages/documentation/current/applications/googleapps.html @@ -135,9 +135,10 @@ Now configure all SAML p
  • Change password URL: where users can change their password. Example: http://auth.example.com
  • - +
    You must check the option Use a specific domain transmitter to force Google Apps to send the full entityId.
    - + +

    Certificate

    @@ -157,7 +158,7 @@ You can now the upload the certificate (cert.pem) on Google Apps.
    You can also use the certificate instead of public key in SAML metadata, see SAML service configuration
    - +

    New Service Provider

    @@ -189,7 +190,7 @@ Now we will add Google Apps as a new Change mydomain.org (in AssertionConsumerService markup, parameter Location) into your Google Apps domain. Also adapt your entityID to match the Assertion issuer: google.com/a/mydomain.org
    - +

    Application menu

    @@ -209,7 +210,7 @@ You need to adapt some parameters:
    Change mydomain.org into your Google Apps domain
    - +

    Logout

    @@ -228,6 +229,6 @@ To manage the other way (LL::NG → Google Ap
    Change mydomain.org into your Google Apps domain
    - + diff --git a/doc/pages/documentation/current/applications/guacamole.html b/doc/pages/documentation/current/applications/guacamole.html new file mode 100644 index 000000000..6550903e5 --- /dev/null +++ b/doc/pages/documentation/current/applications/guacamole.html @@ -0,0 +1,152 @@ + + + + + documentation:2.0:applications:guacamole + + + + + + + + + + + + + + + + + + + + +
    + +
    +

    Table of Contents

    + +
    + + +

    Guacamole

    +
    + +

    + +

    + +
    + +

    Presentation

    +
    + +

    +Apache Guacamole is a web-based remote desktop gateway. It supports standard protocols like VNC, RDP, and SSH. +

    + +

    +As of version 0.9.14, Guacamole can use OpenID Connect , CAS or HTTP Headers as authentication sources through plug-ins. +

    + +

    +This document explains how to implement OpenID Connect +

    + +
    + +

    Pre-requisites

    +
    + +
    + +

    Guacamole

    +
    + +

    +Refer to the official Guacamole documentation to install Guacamole, either manually or through Docker images +

    + +

    +You need to be able to enable extensions. If you are using docker, you need to follow these instructions in order to provide your own extensions directory and Guacamole configuration file +

    + +

    +Your Guacamole configuration directory will look something like this. +

    +
    ├── extensions
    +│   └── 00-guacamole-auth-openid-1.0.0.jar
    +└── guacamole.properties
    +
    Make sure to rename the JAR in a way that ensures that it will be loaded first +
    +

    +And guacamole.properties should contain at least +

    +
    openid-authorization-endpoint: http://auth.example.com/oauth2/authorize
    +openid-jwks-endpoint: http://auth.example.com/oauth2/jwks
    +openid-issuer: http://auth.example.com
    +openid-client-id: guacamole
    +openid-redirect-uri: http://guacamole.example.com/guacamole/
    +openid-username-claim-type: sub
    +
    Remplace the redirect uri with your Guacamole server's URL +
    +
    + +

    LL:NG

    +
    + +

    +Make sure you have already enabled OpenID Connect on your LemonLDAP::NG server +

    + +

    +You also need to allow the Implicit Flow under OpenID Connect Service » Security +

    + +

    +Then, add a Relaying Party with the following configuration +

    +
      +
    • Options » Authentification » Client ID : same as openid-client-id in guacamole.properties
      +
    • +
    • Options » Allowed redirection address : same as openid-redirect-uri in guacamole.properties
      +
    • +
    • Options » ID Token Signature Algorithm : RS512
      +
    • +
    + +
    +
    + + diff --git a/doc/pages/documentation/current/applications/img/icons.png b/doc/pages/documentation/current/applications/img/icons.png index 600317d42..7b81ad0a3 100644 --- a/doc/pages/documentation/current/applications/img/icons.png +++ b/doc/pages/documentation/current/applications/img/icons.png @@ -90,7 +90,7 @@ +
  • @@ -262,7 +262,7 @@ You've followed a link to a topic that doesn't exist yet. If permissio -
    +
    diff --git a/doc/pages/documentation/current/applications/img/loader.gif b/doc/pages/documentation/current/applications/img/loader.gif index 1cd4ad2eb..ceb4433eb 100644 --- a/doc/pages/documentation/current/applications/img/loader.gif +++ b/doc/pages/documentation/current/applications/img/loader.gif @@ -90,7 +90,7 @@ +
  • @@ -262,7 +262,7 @@ You've followed a link to a topic that doesn't exist yet. If permissio -
    +
    diff --git a/doc/pages/documentation/current/applications/zimbra.html b/doc/pages/documentation/current/applications/zimbra.html index 228b87983..3b77b4ac1 100644 --- a/doc/pages/documentation/current/applications/zimbra.html +++ b/doc/pages/documentation/current/applications/zimbra.html @@ -4,7 +4,7 @@ documentation:2.0:applications:zimbra - + diff --git a/doc/pages/documentation/current/authcas.html b/doc/pages/documentation/current/authcas.html index cf4e290f5..34e99bb6e 100644 --- a/doc/pages/documentation/current/authcas.html +++ b/doc/pages/documentation/current/authcas.html @@ -4,7 +4,7 @@ documentation:2.0:authcas - + diff --git a/doc/pages/documentation/current/authcombination.html b/doc/pages/documentation/current/authcombination.html index 945583cc4..df6474312 100644 --- a/doc/pages/documentation/current/authcombination.html +++ b/doc/pages/documentation/current/authcombination.html @@ -4,7 +4,7 @@ documentation:2.0:authcombination - + diff --git a/doc/pages/documentation/current/authgpg.html b/doc/pages/documentation/current/authgpg.html index 6c881f854..795fc332b 100644 --- a/doc/pages/documentation/current/authgpg.html +++ b/doc/pages/documentation/current/authgpg.html @@ -4,7 +4,7 @@ documentation:2.0:authgpg - + diff --git a/doc/pages/documentation/current/authopenidconnect.html b/doc/pages/documentation/current/authopenidconnect.html index 01c377ddf..4703ffc76 100644 --- a/doc/pages/documentation/current/authopenidconnect.html +++ b/doc/pages/documentation/current/authopenidconnect.html @@ -4,7 +4,7 @@ documentation:2.0:authopenidconnect - + diff --git a/doc/pages/documentation/current/authrest.html b/doc/pages/documentation/current/authrest.html index 31945b5a1..cc7d57a75 100644 --- a/doc/pages/documentation/current/authrest.html +++ b/doc/pages/documentation/current/authrest.html @@ -4,7 +4,7 @@ documentation:2.0:authrest - + diff --git a/doc/pages/documentation/current/authsaml.html b/doc/pages/documentation/current/authsaml.html index 666185cde..6260536a2 100644 --- a/doc/pages/documentation/current/authsaml.html +++ b/doc/pages/documentation/current/authsaml.html @@ -4,7 +4,7 @@ documentation:2.0:authsaml - + diff --git a/doc/pages/documentation/current/authssl.html b/doc/pages/documentation/current/authssl.html index 56b064f5d..b51637054 100644 --- a/doc/pages/documentation/current/authssl.html +++ b/doc/pages/documentation/current/authssl.html @@ -4,7 +4,7 @@ documentation:2.0:authssl - + @@ -251,12 +251,12 @@ fastcgi_param SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn; #index index.psgi; location / { try_files $uri $uri/ =404; - add_header Strict-Transport-Security max-age=15768000; + add_header Strict-Transport-Security "max-age=15768000"; } }
    - +

    Configuration of LemonLDAP::NG

    @@ -276,7 +276,7 @@ Then, go in SSL parameters:
    - +

    Auto reloading SSL Certificates

    @@ -384,7 +384,7 @@ $('.enteteBouton').click( function (e) {
    It is incompatible with authentication combination because of Apache parameter “SSLVerifyClient”, which must have the value “require”. To enable SSL with Combination, use SSL by Ajax
    - +

    SSL by Ajax

    @@ -427,6 +427,6 @@ and set :
    - + diff --git a/doc/pages/documentation/current/browseablesessionbackend.html b/doc/pages/documentation/current/browseablesessionbackend.html index 8097c28c5..fdb19bcaa 100644 --- a/doc/pages/documentation/current/browseablesessionbackend.html +++ b/doc/pages/documentation/current/browseablesessionbackend.html @@ -4,7 +4,7 @@ documentation:2.0:browseablesessionbackend - + @@ -92,7 +92,7 @@ The following table list fields to index depending on the feature you want to in - Database cleaup (cron) _session_kind _utime + Database cleanup (cron) _session_kind _utime Session explorer _session_kind ipAddr WHATTOTRACE @@ -106,8 +106,11 @@ The following table list fields to index depending on the feature you want to in Password reset by email user + + SAML Session _saml_id + - +

    See Apache::Session::Browseable::* man page to see how use indexes.

    @@ -116,7 +119,7 @@ See Apache::Session::Browseable::* man page to see how use indexes.
    Documentation below explains how set index on ipAddr and _whatToTrace. Adapt it to configure the index you need.
    - +

    Browseable NoSQL

    @@ -143,15 +146,15 @@ You then just have to add the Index parameter in General par Index Index _whatToTrace ipAddr
    - + - +

    Browseable SQL

    This documentation concerns PostgreSQL. Some adaptations are needed with other databases.
    - +

    Prepare database

    @@ -185,7 +188,7 @@ CREATE INDEX ip1 ON sessions USING BTREE (ipAddr);
    With new Apache::Session::Browseable::PgHstore and PgJSON, you don't need to declare indexes in CREATE TABLE since “json” and “hstore” type are browseable. You should anyway add some indexes (see manpage).
    - +

    Manager

    @@ -214,14 +217,14 @@ Go in the Manager and set the session module ( Index Index _whatToTrace ipAddr _session_kind _utime
    -
    Apache::Session::Browseable::MySQL doesn't use locks so performances are keeped. +
    Apache::Session::Browseable::MySQL doesn't use locks so performances are keeped.

    For databases like PostgreSQL, don't forget to add “Commit” with a value of 1

    - +

    Browseable LDAP

    @@ -275,9 +278,9 @@ You need to add the Index field and can also configure the ld ldapAttributeIndex Attribute storing index ou
    - + - +

    Security

    @@ -290,7 +293,7 @@ You can also use different user/password for your servers by overriding paramete

    - +

    Performances

    @@ -332,6 +335,6 @@ CREATE INDEX _u1 ON sessions (_utime); CREATE INDEX ip1 ON sessions (ipAddr) USING BTREE;
    - + diff --git a/doc/pages/documentation/current/contribute.html b/doc/pages/documentation/current/contribute.html index 7d690f29f..40f7bc8d8 100644 --- a/doc/pages/documentation/current/contribute.html +++ b/doc/pages/documentation/current/contribute.html @@ -4,7 +4,7 @@ documentation:2.0:contribute - + diff --git a/doc/pages/documentation/current/documentation/oauth-retina-preview.5ca2e2d7241bbcec7d492df10866fdd3.jpeg b/doc/pages/documentation/current/documentation/oauth-retina-preview.5ca2e2d7241bbcec7d492df10866fdd3.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9342acafdd0d4b6f2c07550bf5fdbca11b991124 GIT binary patch literal 9158 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 MP5a-Bp7`f~0qbznZ2$lO literal 0 HcmV?d00001 diff --git a/doc/pages/documentation/current/documentation/oauth2_handler.png b/doc/pages/documentation/current/documentation/oauth2_handler.png new file mode 100644 index 0000000000000000000000000000000000000000..7c3d485c31703efcdc095f924d60ee9924eba791 GIT binary patch literal 52860 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

    Zp|kMk+vev6X;`M$9K}O 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

    +
  • @@ -262,7 +262,7 @@ You've followed a link to a topic that doesn't exist yet. If permissio -
    +
    diff --git a/doc/pages/documentation/current/exploit b/doc/pages/documentation/current/exploit index 870055030..540b65452 100644 --- a/doc/pages/documentation/current/exploit +++ b/doc/pages/documentation/current/exploit @@ -90,7 +90,7 @@ +
  • @@ -262,7 +262,7 @@ You've followed a link to a topic that doesn't exist yet. If permissio -
    +
    diff --git a/doc/pages/documentation/current/external2f.html b/doc/pages/documentation/current/external2f.html index f3627f035..00219b8e8 100644 --- a/doc/pages/documentation/current/external2f.html +++ b/doc/pages/documentation/current/external2f.html @@ -4,7 +4,7 @@ documentation:2.0:external2f - + @@ -43,6 +43,23 @@
    + +
    +

    Table of Contents

    +
    + + +
    +
    +

    External Second Factor

    @@ -84,6 +101,27 @@ All parameters are configured in “General Parameters » Portal Parameters » E
    The command line is split in an array and launched with exec(). So you don't need to enclose arguments in “” and this feature protects your system against shell injection. However, you can not use any space except to separate arguments.
    +
    + +

    SELinux note

    +
    + +

    +If your server is enforcing SELinux policies, make sure your external script has a label that is allowed to be executed by httpd. +

    + +

    +For example, storing your script in /usr/local/bin/ will give it a bin_t label that will work correctly. +

    + +

    +If your script has a httpd_sys_script_exec_t type, it will only be able to do external network requests if the SELinux boolean httpd_can_network_connect is enabled. +

    + +

    +If your script has any other label, it will probably not work at all. +

    +
    diff --git a/doc/pages/documentation/current/grantsession.html b/doc/pages/documentation/current/grantsession.html new file mode 100644 index 000000000..865b198b4 --- /dev/null +++ b/doc/pages/documentation/current/grantsession.html @@ -0,0 +1,87 @@ + + + + + documentation:2.0:grantsession + + + + + + + + + + + + + + + + + + + + +
    + +

    Grant Session

    +
    + +
    + +

    Presentation

    +
    + +

    +The goal of this plugin is to evaluate different conditions before allowing a user to open a session on the portal. When a condition is not met, then the user is prompted with a customized message. +

    + +
    + +

    Configuration

    +
    + +

    +This plugin is enabled by default. +

    + +

    +To configure rules, go in General Parameters > Sessions > Opening conditions. +

    + +

    +You can then create rules with these fields: +

    +
      +
    • Comment: a label for your rule, than can be used to order it (rules are evaluated by alphabetical order).
      +
    • +
    • Rule: The condition that will be evaluated. If this condition does not return true, then the session is refused.
      +
    • +
    • Message: The message that will be displayed. That message can contain session data as user attributes or macros.
      +
    • +
    + +
    +
    + + diff --git a/doc/pages/documentation/current/handlerarch.html b/doc/pages/documentation/current/handlerarch.html index 0a996a8eb..e63e8ae77 100644 --- a/doc/pages/documentation/current/handlerarch.html +++ b/doc/pages/documentation/current/handlerarch.html @@ -68,23 +68,23 @@ Handlers are build on rows of modules:
    - + - + - + - +
    Platform Wrapper Types Main Usage Platform Wrapper Types Main
    Applications Launchers
    ApacheMP2 ApacheMP2::<type> Lib::<type> Main Apache2 protection ApacheMP2 ApacheMP2::<type> Lib::<type> Main
    Server Server::<type> Plack servers protection or Nginx/SSOaaS FastCGI/uWSGI server Server Server::<type>
    PSGI PSGI::<type> Self protected applications PSGI PSGI::<type>
    - +

    Types are:

    diff --git a/doc/pages/documentation/current/handlerauthbasic.html b/doc/pages/documentation/current/handlerauthbasic.html index da06cb2e4..c1af21aa3 100644 --- a/doc/pages/documentation/current/handlerauthbasic.html +++ b/doc/pages/documentation/current/handlerauthbasic.html @@ -4,7 +4,7 @@ documentation:2.0:handlerauthbasic - + diff --git a/doc/pages/documentation/current/idpcas.html b/doc/pages/documentation/current/idpcas.html index 203579bf5..5c26b5dc5 100644 --- a/doc/pages/documentation/current/idpcas.html +++ b/doc/pages/documentation/current/idpcas.html @@ -65,14 +65,12 @@
    -

    -AS server -

    +

    CAS server

    - -

    Presentation

    + +

    Presentation

    @@ -90,13 +88,13 @@ AS server

    - -

    Configuration

    + +

    Configuration

    - -

    Enabling CAS

    + +

    Enabling CAS

    @@ -115,15 +113,15 @@ In the Manager, go in General Parameters » Issuer modules

    - -

    Configuring the CAS Service

    + +

    Configuring the CAS Service

    Then go in CAS Service to define:

      -
    • CAS login: the session key transmitted to CAS client as the main identifier (CAS Principal)
      +
    • CAS login: the session key transmitted to CAS client as the main identifier (CAS Principal). This setting can be overriden per-application.
    • CAS attributes: list of attributes that will be transmitted by default in the validate response. Keys are the name of attribute in the CAS response, values are the name of session key.
    • @@ -143,8 +141,8 @@ Then go in CAS Service
      If CAS login is not set, it uses General Parameters » Logs » REMOTE_USER data, which is set to uid by default
    - -

    Configuring CAS Applications

    + +

    Configuring CAS Applications

    @@ -166,6 +164,8 @@ You can then access the configuration of this application.

    • Service URL : the service (user-facing) URL of the CAS-enabled application.
    • +
    • User attribute : session field that will be used as main identifier.
      +
    • Rule : The access control rule to enforce on this application. If left blank, access will be allowed for everyone.
    @@ -185,6 +185,6 @@ The attributes defined here will completely replace any attributes you may have

    - + diff --git a/doc/pages/documentation/current/idpopenidconnect.html b/doc/pages/documentation/current/idpopenidconnect.html index 3ed8f4051..cb923e0a2 100644 --- a/doc/pages/documentation/current/idpopenidconnect.html +++ b/doc/pages/documentation/current/idpopenidconnect.html @@ -108,15 +108,21 @@ As an OP, LL::NG supports a lot of OpenID Con
  • Session management
  • +
  • FrontChannel Logout
    +
  • +
  • BackChannel Logout
    +
  • +
  • PKCE (Since 2.0.4)
    +
  • - +

    Configuration

    - +

    OpenID Connect Service

    - +

    Configuration of LL::NG in Relying Party

    @@ -227,7 +233,7 @@ An example of its content: }
    - +

    Configuration of Relying Party in LL::NG

    @@ -372,6 +378,10 @@ You can also define extra claims and link them to attributes (see below). Then y
  • Client secret: Client secret for this RP (can be use for symmetric signature)
  • +
  • Public client (since version 2.0.4): set this RP as public client, so authentication is not needed on token endpoint
    +
  • +
  • +
  • Display:
    @@ -382,7 +392,7 @@ You can also define extra claims and link them to attributes (see below). Then y
  • -
  • User attribute: session field that with be used as main identifier (sub)
    +
  • User attribute: session field that will be used as main identifier (sub)
  • ID Token signature algorithm: Select one of none, HS256, HS384, HS512, RS256, RS384, RS512
  • @@ -406,6 +416,6 @@ Associate attributes to extra claims if the RP request them, for example b

    - + diff --git a/doc/pages/documentation/current/impersonation.html b/doc/pages/documentation/current/impersonation.html index 915b4e414..1fcb0a439 100644 --- a/doc/pages/documentation/current/impersonation.html +++ b/doc/pages/documentation/current/impersonation.html @@ -79,18 +79,26 @@ Just enable it in the Manager (section “plugins”) by setting a rule. Imperso
    You HAVE TO modify REMOTE_USER to log both real AND spoofed uid.

    -Set a macro like this : _whatToTrace -> $real__user ? "$real__user/$_user" : $_user +Set a macro like this : +

    + +

    + _whatToTrace -> $real__user ? "$real__user / $_user" : $_user / $_user

    and set Genaral Parameters > Logs > REMOTE_USER with _whatToTrace

    -
    Both spoofed and real profile attributes can be used to set access rules, groups or macros. +
    Both spoofed and real session attributes can be used to set access rules, groups or macros.

    By example : $real_uid eq 'dwho' or $real_groups =~ /\bsu\b/

    +

    +Keep in mind that real session is computed first. Afterward, if access is granted, impersonated session is computed with real and spoofed session attributes if Impersonation is allowed. +

    +
    By example, to prevent impersonation with 'dwho' set Identities use rule like :

    $uid ne 'dwho' diff --git a/doc/pages/documentation/current/mitm b/doc/pages/documentation/current/mitm index eacfe4863..ff6ea74e4 100644 --- a/doc/pages/documentation/current/mitm +++ b/doc/pages/documentation/current/mitm @@ -90,7 +90,7 @@

    +
  • @@ -262,7 +262,7 @@ You've followed a link to a topic that doesn't exist yet. If permissio -
    +
    diff --git a/doc/pages/documentation/current/oauth2handler.html b/doc/pages/documentation/current/oauth2handler.html new file mode 100644 index 000000000..59d7504d4 --- /dev/null +++ b/doc/pages/documentation/current/oauth2handler.html @@ -0,0 +1,97 @@ + + + + + documentation:2.0:oauth2handler + + + + + + + + + + + + + + + + + + + + +
    + +

    OAuth2 Handler

    +
    + +

    + +

    + +
    + +

    Presentation

    +
    + +

    +This Handler is able to check an OAuth2 access token to retrieve the user real session and protect a virtual host like a standard Handler (access control and HTTP headers transmission). +

    + +

    +This requires to get an OAuth2 access token trough LL::NG Portal (OpenID Connect server). This access token can then be used in the Authorization header to authenticate to the Web Service / API protected by the OAuth2 Handler. +

    + +

    + +

    +
    In the above schema, the OpenID Connect process is simplified. How the front application receives the Access Token depends on the requested flow (Authorization code, Implicit or Hybrid). In all cases, the application will have an Access Token and will be able to use it to request a Web Service. +
    +

    +Example: +

    +
    curl -H "Authorization: Bearer de853461341e88e9def8fcb9db2a81c4" https://oauth2.example.com/api/test | json_pp
    +
    {
    +    check: true,
    +    user: "dwho"
    +}
    + +
    + +

    Configuration

    +
    + +

    +Protect you virtual host like any other virtual host with the standard Handler. +

    + +

    +Define access rules and headers. Then in Options > Type, choose OAuth2. +

    + +
    +
    + + diff --git a/doc/pages/documentation/current/parameterlist.html b/doc/pages/documentation/current/parameterlist.html index 8b972f23b..438d147d0 100644 --- a/doc/pages/documentation/current/parameterlist.html +++ b/doc/pages/documentation/current/parameterlist.html @@ -4,7 +4,7 @@ documentation:2.0:parameterlist - + diff --git a/doc/pages/documentation/current/performances.html b/doc/pages/documentation/current/performances.html index 431a3732d..78eee0909 100644 --- a/doc/pages/documentation/current/performances.html +++ b/doc/pages/documentation/current/performances.html @@ -4,7 +4,7 @@ documentation:2.0:performances - + @@ -49,7 +49,11 @@
    -

    Handler performance

    +

    Cron optimization

    +
    + +

    +LLNG installs its cron files without knowing how many servers are installed. You should optimize this to launch: +

    +
      +
    • purgeCentralCache: only 1 time every 10 minutes for the whole system
      +
    • +
    • purgeLocalCache: ~ 1 time per hour on each server
      +
    • +
    + +
    + +

    Handler performance

    @@ -123,8 +142,8 @@ Handlers check rights and calculate headers for each HTTP hit. So to improve per

    - -

    Macros and groups

    + +

    Macros and groups

    @@ -184,8 +203,8 @@ admin -> $uid Macros and groups are computed in alphanumeric order, that is, in the order they are displayed in the manager. For example, macro “macro1” will be computed before macro “macro2”: so, expression of macro2 may involve value of macro1. As same for groups: a group rule may involve another, previously computed group.

    - -

    Local macros

    + +

    Local macros

    @@ -198,13 +217,13 @@ Display-Name -> Note that this feature is interesting only for the Lemonldap::NG systems protecting a high number of applications

    - -

    Portal performances

    + +

    Portal performances

    - -

    General performances

    + +

    General performances

    @@ -226,8 +245,8 @@ By default it uses local storage to store its tokens. If you have more than 1 po

    - -

    Apache::Session performances

    + +

    Apache::Session performances

    -
      +
      • (1) : “purge” test is done with Apache::Session::Browseable-1.2.5 and LLG-2.0. Earlier results are not so good.
      • (2) : “purge” test is done with Apache::Session::Browseable-1.2.6 and LLG-2.0.
        @@ -362,8 +381,8 @@ Analysis:
      - -

      LDAP performances

      + +

      LDAP performances

      @@ -399,13 +418,13 @@ Now ldapgroups contains “admin su”

      - -

      Manager performances

      + +

      Manager performances

      - -

      Disable unused modules

      + +

      Disable unused modules

      @@ -415,8 +434,8 @@ In lemonldap-ng.ini, set only modules that you will use. By default, configurati enabledModules = conf, sessions

      - -

      Use static HTML files

      + +

      Use static HTML files

      @@ -442,6 +461,6 @@ So manager HTML templates will be

      - + diff --git a/doc/pages/documentation/current/plugincustom.html b/doc/pages/documentation/current/plugincustom.html index f73c11de7..6158acff3 100644 --- a/doc/pages/documentation/current/plugincustom.html +++ b/doc/pages/documentation/current/plugincustom.html @@ -4,7 +4,7 @@ documentation:2.0:plugincustom - + @@ -88,6 +88,32 @@ You can now write a custom portal plugin that will hook in the authentication pr
    +

    +If you need to call a method just after any standard method in authentication process, then use afterSub, for example: +

    +
      use constant afterSub => {
    +      getUser => 'mysub',
    +  }
    +  sub mysub {
    +      my ( $self ,$req ) = @_;
    +      # Do something
    +      return PE_OK;
    +  }
    + +

    +If you need to call a method instead any standard method in authentication process, then use aroundSub, for example: +

    +
      use constant aroundSub => {
    +      getUser => 'mysub',
    +  };
    +  sub mysub {
    +      my ( $self, $sub, $req ) = @_;
    +      # Do something before
    +      my $ret = $sub->($req);
    +      # Do something after
    +      return $ret;
    +  }
    +

    The plugin can also define new routes and call actions on them.

    @@ -97,12 +123,12 @@ See also Lemonldap::NG::Portal::Main::Plugin man page.

    - +

    Example

    - +

    Plugin Perl module

    @@ -147,7 +173,7 @@ extends 'Lemonldap::NG::Portal::Main::Plugin'1;
    - +

    Configuration

    @@ -160,6 +186,6 @@ customPlugins = Lemonldap::;customPlugins = Lemonldap::NG::Portal::MyPlugin1, Lemonldap::NG::Portal::MyPlugin2, ...
    - + diff --git a/doc/pages/documentation/current/portalcustom.html b/doc/pages/documentation/current/portalcustom.html index 6ecc6c9ad..a376a03f1 100644 --- a/doc/pages/documentation/current/portalcustom.html +++ b/doc/pages/documentation/current/portalcustom.html @@ -4,7 +4,7 @@ documentation:2.0:portalcustom - + @@ -299,11 +299,11 @@ You can also define messages in several languages or disable message boxes by us

    -If you have a custom skin, then you can create a lang file in templates/<your skin similar to the default lang files provided in htdocs/static/languages/. +If you have a custom skin, then you can create a lang file in templates/<your skin> similar to the default lang files provided in htdocs/static/languages/.

    -For example htdocs/static/languages/en.json: +For example templates/myskin/en.json:

    {
     "PE9":"Please authenticate!"
    @@ -314,7 +314,7 @@ You can also create a file called all.json to override messages in
     

    - +
    @@ -330,7 +330,7 @@ This will allow one to display the tab directly with this +

    Template parameters

    @@ -358,7 +358,7 @@ You can also display environment variables, with the prefix env_:
    Your IP is <TMPL_VAR NAME="env_REMOTE_ADDR">
    - +

    Buttons

    @@ -375,7 +375,7 @@ This node allows one to enable/disable buttons on the login page:
    - +

    Password management

      @@ -388,7 +388,7 @@ This node allows one to enable/disable buttons on the login page:
    - +

    Other parameters

      @@ -407,6 +407,6 @@ This node allows one to enable/disable buttons on the login page:
    -
    + diff --git a/doc/pages/documentation/current/portalmenu.html b/doc/pages/documentation/current/portalmenu.html index eff1861da..63ca062b6 100644 --- a/doc/pages/documentation/current/portalmenu.html +++ b/doc/pages/documentation/current/portalmenu.html @@ -123,7 +123,7 @@ Application parameters:

    -
    The chosen logo file must be in portal applications logos directory (portal/static/common/apps/). You can set a custom logo by setting the logo file name directly in the field, and copy the logo file in portal applications logos directory +
    The chosen logo file must be in portal applications logos directory (portal/htdocs/static/common/apps/). You can set a custom logo by setting the logo file name directly in the field, and copy the logo file in portal applications logos directory
    diff --git a/doc/pages/documentation/current/portalservers.html b/doc/pages/documentation/current/portalservers.html index acc361a22..e381e4fdf 100644 --- a/doc/pages/documentation/current/portalservers.html +++ b/doc/pages/documentation/current/portalservers.html @@ -72,21 +72,23 @@ LL::NG portal can be configured as REST or (deprecated) SOAP server, for several usage:

      -
    • Configuration sharing
      +
    • Configuration access
    • -
    • Sessions sharing
      +
    • Sessions access
      +
    • +
    • Authentication
    • Specific application needs
    - +

    Configuration

    - +

    REST

    diff --git a/doc/pages/documentation/current/resetpassword.html b/doc/pages/documentation/current/resetpassword.html index fb48a9da8..361162299 100644 --- a/doc/pages/documentation/current/resetpassword.html +++ b/doc/pages/documentation/current/resetpassword.html @@ -94,10 +94,10 @@ The SMTP server must be setup, see
    Mail content:
    +
  • Password reset mail content:
    - +

    Configure security settings

    @@ -411,7 +412,7 @@ requireToken => $env->{REMOTE_ADDR} !~ /^127\.0\.[1-3]\.1$/
    - +

    Fail2ban

    @@ -463,7 +464,7 @@ Restart fail2ban

    - +

    Sessions identifier

    @@ -476,7 +477,7 @@ We recommend to use : Lemonldap::NG::Common::Apache::Session::Generate::SH

    - +

    SAML

    @@ -485,6 +486,6 @@ See
    + diff --git a/doc/pages/documentation/current/selfmadeapplication.html b/doc/pages/documentation/current/selfmadeapplication.html index 317bdb8d3..c335eb172 100644 --- a/doc/pages/documentation/current/selfmadeapplication.html +++ b/doc/pages/documentation/current/selfmadeapplication.html @@ -121,7 +121,7 @@ First create a PSGI module based on Lemonldap::NG::Handler:

    package My::PSGI;
      
    -use base "Lemonldap::NG::Handler::PSGI";
    +use base "Lemonldap::NG::Handler::PSGI"; # or Lemonldap::NG::Handler::PSGI::OAuth2, etc…
      
     sub init {
         my ($self,$args) = @_;
    diff --git a/doc/pages/documentation/current/sessions.html b/doc/pages/documentation/current/sessions.html
    index 9f159a574..bc7f2f171 100644
    --- a/doc/pages/documentation/current/sessions.html
    +++ b/doc/pages/documentation/current/sessions.html
    @@ -66,7 +66,7 @@ To configure sessions, go in Manager, General Parameters » S
     
     
    Session activity timeout requires Handlers to have a write access to sessions database.
      -
    • Opening conditions: rules which are evaluated before granting session. If a user does not comply with any condition, he is prompted a customized message. That message can contain session data as user attributes or macros. The conditions are checked in alphabetical order of comments.
      +
    • Opening conditions: rules which are evaluated before granting session, see Grant Session plugin documentation
    • Sessions Storage: you can define here which session backend to use, with the backend options. See sessions database configuration to know which modules you can use. Here are some global options that you can use with all sessions backends:
        @@ -94,7 +94,7 @@ To configure sessions, go in Manager, General Parameters » S
        Note that since HTTP protocol is not connected, restrictions are not applied to the new session: the oldest are destroyed.
        - +

        Command-line tools

          @@ -109,6 +109,6 @@ $ llngDeleteSession dh* $ llngDeleteSession *
    - + diff --git a/doc/pages/documentation/current/smtp.html b/doc/pages/documentation/current/smtp.html index b13bb8940..1c7251b6c 100644 --- a/doc/pages/documentation/current/smtp.html +++ b/doc/pages/documentation/current/smtp.html @@ -48,10 +48,12 @@

    -Go in General Parameters > Extended Parameters > SMTP +Go in General Parameters > Advanced Parameters > SMTP:

      -
    • SMTP Server: IP or hostname of the SMTP server
      +
    • Session key containing mail address: choose which session field contains mail address
      +
    • +
    • SMTP Server: IP or hostname of the SMTP server
    • SMTP Port: Port of the SMTP server
    • @@ -59,13 +61,15 @@ Go in General Parameters > Extended Parameters > SMTP
    • SMTP Password: SMTP password if authentication is required
    • +
    • SSL/TLS protocol and SSL/TLS options: Here you can enable SMTPS or startTLS
      +
    • If no SMTP server is configured, the mail will be sent via the local sendmail program. Else, Net::SMTP module is required to use the SMTP server
    • The SMTP server value can hold the port, for example: mail.example.com:25
    • -
    • If authentication is configured, Authen::SASL and MIME::Base64 modules are required
      +
    • If authentication is configured, Authen::SASL and MIME::Base64 modules are required
    @@ -76,7 +80,7 @@ Go in General Parameters > Extended Parameters > SMTP
  • Reply address: address seen in the “Reply-To” field
  • -
  • Mail charset: Charset used for the body of the mail (default: utf-8)
    +
  • charset: Charset used for the body of the mail (default: utf-8)
  • diff --git a/doc/pages/documentation/current/start.html b/doc/pages/documentation/current/start.html index 3ab5fc10e..9690c082b 100644 --- a/doc/pages/documentation/current/start.html +++ b/doc/pages/documentation/current/start.html @@ -529,7 +529,7 @@ Force Authentication Force authentication to access to Portal - Grant Sessions rules + Grant Sessions Rules to apply before allowing a user to open a session Impersonation Allow users to use another identity @@ -559,13 +559,13 @@ Upgrade session Plugin that explain to user that a more secure authentication is needed instead of rejected it - +

    - +

    Handlers

    @@ -581,45 +581,50 @@ Handlers are software control agents to be installed on your web servers (Ng
    - + - + - + - + - + - + - + - + + + +
    Handler type Apache Nginx Plack* servers Node.js Comment Handler type Apache Nginx Plack* servers Node.js Self protected apps Comment
    Main (default handler) Partial (*) Main (default handler) Partial (1)
    AuthBasic Designed for some server-to-server applications AuthBasic Designed for some server-to-server applications
    CDA For Cross Domain Authentication CDA For Cross Domain Authentication
    DevOps (SSOaaS) Allows application developers to define their own rules and headers inside their applications DevOps (SSOaaS) Allows application developers to define their own rules and headers inside their applications
    DevOpsST (SSOaaS) Enables both DevOps and Service Token DevOpsST (SSOaaS) Enables both DevOps and Service Token
    Secure Token Designed to secure exchanges between a LLNG reverse-proxy and a remote app OAuth2 (2) Uses OpenID Connect/OAuth2 access token to check authentication and authorization, can be used to protect Web Services
    Service Token (Server-to-Server) Designed to permit underlying requests (API-Based Infrastructure) Secure Token Designed to secure exchanges between a LLNG reverse-proxy and a remote app
    Service Token (Server-to-Server) Designed to permit underlying requests (API-Based Infrastructure)
    Zimbra PreAuth
    - -

    -(*): Node.js handler has not yet reached the same level of functionalities. -

    +

    - +

    LLNG databases

    @@ -668,7 +673,7 @@ Handlers are software control agents to be installed on your web servers (Ng Local Use only lemonldap-ng.ini parameters.
    -
    You can not start with an empty configuration, so read how to change configuration backend to convert your existing configuration into another one. +
    You can not start with an empty configuration, so read how to change configuration backend to convert your existing configuration into another one.

    @@ -723,13 +728,13 @@ Sessions are stored using +

    Applications protection

    @@ -758,7 +763,7 @@ Sessions are stored using +

    Well known compatible applications

    -
    +
    From 07de622e832fb19bbb138d4efdf63c00ed438675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20OUDOT?= Date: Sun, 12 May 2019 17:36:14 +0200 Subject: [PATCH 10/19] Fix getRegisterSession and getMailSession (#1743) --- .../lib/Lemonldap/NG/Portal/Lib/SMTP.pm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm index ddb859f6b..f0a7c68c5 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm @@ -15,7 +15,7 @@ use Email::Sender::Transport::SMTP qw(); use MIME::Base64; use Encode; -our $VERSION = '2.0.3'; +our $VERSION = '2.0.4'; our $transport; @@ -184,7 +184,7 @@ sub send_mail { foreach ( keys %cid ) { $message->attach( Type => "image/" . ( $cid{$_} =~ m/\.(\w+)/ )[0], - Id => $_, + Id => $_, Path => $self->conf->{templateDir} . "/" . $self->conf->{portalSkin} . "/" . $cid{$_}, @@ -234,7 +234,8 @@ sub getMailSession { # Browse found sessions to check if it's a mail session foreach my $id ( keys %$sessions ) { - my $mailSession = $self->p->getApacheSession($id); + my $mailSession = + $self->p->getApacheSession( $id, ( kind => "TOKEN" ) ); next unless ($mailSession); return $mailSession if ( $mailSession->data->{_type} =~ /^mail$/ ); } @@ -259,7 +260,8 @@ sub getRegisterSession { # Browse found sessions to check if it's a register session foreach my $id ( keys %$sessions ) { - my $registerSession = $self->p->getApacheSession($id); + my $registerSession = + $self->p->getApacheSession( $id, ( kind => "TOKEN" ) ); next unless ($registerSession); return $id if ( $registerSession->data->{_type} From 682b19347762b925e29e68f20468cc3a0f50f620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20OUDOT?= Date: Sun, 12 May 2019 20:04:38 +0200 Subject: [PATCH 11/19] Use TOKEN kind for mail password reset sessions (#1743) --- .../lib/Lemonldap/NG/Portal/Plugins/MailPasswordReset.pm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/MailPasswordReset.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/MailPasswordReset.pm index 1188d91c4..9d37067da 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/MailPasswordReset.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/MailPasswordReset.pm @@ -28,7 +28,7 @@ use Lemonldap::NG::Portal::Main::Constants qw( PE_USERNOTFOUND ); -our $VERSION = '2.0.3'; +our $VERSION = '2.0.4'; extends 'Lemonldap::NG::Portal::Main::Plugin', 'Lemonldap::NG::Portal::Lib::SMTP', 'Lemonldap::NG::Portal::Lib::_tokenRule'; @@ -112,7 +112,8 @@ sub _reset { $self->logger->debug("Token given for password reset: $mailToken"); # Check if token is valid - my $mailSession = $self->p->getApacheSession($mailToken); + my $mailSession = + $self->p->getApacheSession( $mailToken, kind => "TOKEN" ); unless ($mailSession) { $self->userLogger->warn('Bad reset token'); return PE_BADMAILTOKEN; @@ -251,7 +252,8 @@ sub _reset { $infos->{_pdata} = $req->pdata; # create session - $mailSession = $self->p->getApacheSession( undef, info => $infos ); + $mailSession = + $self->p->getApacheSession( undef, kind => "TOKEN", info => $infos ); $req->id( $mailSession->id ); } From 05cd4d4a5828345449aba15e98363227f71b2298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20OUDOT?= Date: Sun, 12 May 2019 20:39:25 +0200 Subject: [PATCH 12/19] Fix update token with global storage (#1742) --- lemonldap-ng-portal/MANIFEST | 1 + .../Lemonldap/NG/Portal/Lib/OneTimeToken.pm | 8 ++- .../t/77-2F-Mail-with-global-storage.t | 70 +++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 lemonldap-ng-portal/t/77-2F-Mail-with-global-storage.t diff --git a/lemonldap-ng-portal/MANIFEST b/lemonldap-ng-portal/MANIFEST index 541cb12cc..d93949b89 100644 --- a/lemonldap-ng-portal/MANIFEST +++ b/lemonldap-ng-portal/MANIFEST @@ -536,6 +536,7 @@ t/76-2F-Ext-with-BruteForce.t t/76-2F-Ext-with-CodeActivation.t t/76-2F-Ext-with-GrantSession.t t/76-2F-Ext-with-History.t +t/77-2F-Mail-with-global-storage.t t/77-2F-Mail.t t/90-Translations.t t/99-pod.t diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OneTimeToken.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OneTimeToken.pm index 2539c4724..558891188 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OneTimeToken.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/OneTimeToken.pm @@ -5,7 +5,7 @@ use Mouse; use JSON qw(from_json to_json); use Crypt::URandom; -our $VERSION = '2.0.2'; +our $VERSION = '2.0.4'; extends 'Lemonldap::NG::Common::Module'; @@ -134,7 +134,11 @@ sub updateToken { return $id; } else { - $self->p->getApacheSession( $id, $k => $v ); + $self->p->getApacheSession( + $id, + kind => "TOKEN", + info => { $k => $v } + ); return $id; } } diff --git a/lemonldap-ng-portal/t/77-2F-Mail-with-global-storage.t b/lemonldap-ng-portal/t/77-2F-Mail-with-global-storage.t new file mode 100644 index 000000000..0e8c9cd89 --- /dev/null +++ b/lemonldap-ng-portal/t/77-2F-Mail-with-global-storage.t @@ -0,0 +1,70 @@ +use Test::More; +use strict; +use IO::String; +use Data::Dumper; + +require 't/test-lib.pm'; +require 't/smtp.pm'; + +use_ok('Lemonldap::NG::Common::FormEncode'); +count(1); + +my $client = LLNG::Manager::Test->new( { + ini => { + logLevel => 'error', + mail2fActivation => 1, + mail2fCodeRegex => '\d{4}', + authentication => 'Demo', + userDB => 'Same', + tokenUseGlobalStorage => 1, + } + } +); + +# Try to authenticate +# ------------------- +ok( + my $res = $client->_post( + '/', + IO::String->new('user=dwho&password=dwho'), + length => 23, + accept => 'text/html', + ), + 'Auth query' +); +count(1); + +my ( $host, $url, $query ) = + expectForm( $res, undef, '/mail2fcheck', 'token', 'code' ); + +ok( + $res->[2]->[0] =~ +qr%%, + 'Found EXTCODE input' +) or print STDERR Dumper( $res->[2]->[0] ); +count(1); + +ok( mail() =~ m%(\d{4})%, 'Found 2F code in mail' ) + or print STDERR Dumper( mail() ); + +my $code = $1; +count(1); + +$query =~ s/code=/code=${code}/; +ok( + $res = $client->_post( + '/mail2fcheck', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Post code' +); +count(1); +my $id = expectCookie($res); +$client->logout($id); + +clean_sessions(); + +done_testing( count() ); + From 95c08b89e787a8d59993c00caf8ffdc4d48ef79a Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Sun, 12 May 2019 21:07:47 +0200 Subject: [PATCH 13/19] Rename vars to be more consistent --- .../lib/Lemonldap/NG/Manager/Viewer.pm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Viewer.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Viewer.pm index cd06bacac..c7dbfd7f9 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Viewer.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Viewer.pm @@ -25,9 +25,9 @@ sub addRoutes { my ( $self, $conf ) = @_; $self->ua( Lemonldap::NG::Common::UserAgent->new($conf) ); - my $hiddenPK = ''; - $hiddenPK = $self->{viewerHiddenKeys}; - my @enabledPK = (); + my $hiddenKeys = ''; + $hiddenKeys = $self->{viewerHiddenKeys}; + my @enabledKeys = (); my @keys = qw(virtualHosts samlIDPMetaDataNodes samlSPMetaDataNodes applicationList oidcOPMetaDataNodes oidcRPMetaDataNodes casSrvMetaDataNodes casAppMetaDataNodes @@ -37,12 +37,12 @@ sub addRoutes { foreach (@keys) { # Ignore hidden ConfTree Primary Keys - push @enabledPK, $_ - unless ( $hiddenPK =~ /\b$_\b/ ); + push @enabledKeys, $_ + unless ( $hiddenKeys =~ /\b$_\b/ ); } # Forbid hidden keys - foreach ( split /\s+/, $hiddenPK ) { + foreach ( split /\s+/, $hiddenKeys ) { $self->addRoute( view => { ':cfgNum' => { $_ => 'rejectKey' } }, ['GET'] @@ -57,7 +57,7 @@ sub addRoutes { # Special keys ->addRoute( view => { - ':cfgNum' => \@enabledPK + ':cfgNum' => \@enabledKeys }, ['GET'] ) From fc034ad4bf61a2d3ad5a5797cceab0969a448dde Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Sun, 12 May 2019 22:59:21 +0200 Subject: [PATCH 14/19] Impersonation with doubleCookie (#1746) --- .../lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm index b3316f5b5..ec1fc20c8 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm @@ -141,9 +141,12 @@ sub run { $req->steps( [ $self->p->validSession, @{ $self->p->endAuth } ] ); # Restore _httpSession for double Cookies - $req->{sessionInfo}->{_httpSession} = - $req->{sessionInfo}->{real__httpSession} - if $req->{sessionInfo}->{real__httpSession}; + if ( $self->conf->{securedCookie} >= 2 ) { + $self->p->updateSession( $req, $spoofSession, + $req->{sessionInfo}->{real__httpSession} ); + $req->{sessionInfo}->{_httpSession} = + $req->{sessionInfo}->{real__httpSession}; + } return $statut; } From 1f1eeab9c898609763144c83cf57d73f12f6a3d6 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Tue, 14 May 2019 19:47:28 +0200 Subject: [PATCH 15/19] Do not log a warning when displaying form with Combination When form-based authentication methods return PE_FIRSTLOGIN, do not log a warning because it's normal behavior to show the form. --- .../lib/Lemonldap/NG/Portal/Auth/Combination.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Combination.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Combination.pm index 4d128f2d6..6ef1c507e 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Combination.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Combination.pm @@ -3,7 +3,7 @@ package Lemonldap::NG::Portal::Auth::Combination; use strict; use Mouse; use Lemonldap::NG::Common::Combination::Parser; -use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_ERROR); +use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_ERROR PE_FIRSTACCESS); use Scalar::Util 'weaken'; our $VERSION = '2.0.3'; @@ -197,7 +197,7 @@ sub try { $req->sessionInfo->{ [ '_auth', '_userDB' ]->[$type] } = $name; $req->sessionInfo->{_combinationTry} = $req->data->{dataKeep}->{combinationTry}; - if ( $res > 0 ) { + if ( $res > 0 and $res != PE_FIRSTACCESS ) { $self->userLogger->warn( 'All schemes failed' . ( $req->user ? ' for user ' . $req->user : '' ) ); } From cf297736b5fd4ff93c3a8188452465bb8d7e80e4 Mon Sep 17 00:00:00 2001 From: Xavier Date: Tue, 14 May 2019 22:05:30 +0200 Subject: [PATCH 16/19] Improve cli logs (#1750) --- lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm index 45173a928..e54d00f70 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm @@ -31,6 +31,8 @@ has yes => ( is => 'rw', isa => 'Bool', default => 0 ); has force => ( is => 'rw', isa => 'Bool', default => 0 ); +has log => ( is => 'rw' ); + sub get { my ( $self, @keys ) = @_; die 'get requires at least one key' unless (@keys); @@ -250,10 +252,10 @@ sub _save { } $new->{cfgAuthor} = 'lmConfigEditor: ' . `whoami`; chomp $new->{cfgAuthor}; - $new->{cfgAuthorIP} = ''; + $new->{cfgAuthorIP} = '127.0.0.1'; $new->{cfgDate} = time; - $new->{cfgVersion} = $VERSION; - $new->{cfgLog} = ''; + $new->{cfgVersion} = $Lemonldap::NG::Manager::VERSION; + $new->{cfgLog} = $self->log || ''; $new->{key} ||= join( '', map { chr( int( ord( Crypt::URandom::urandom(1) ) * 94 / 256 ) + 33 ) } ( 1 .. 16 ) ); @@ -395,6 +397,10 @@ Set it to 1 to save a configuration earlier than latest Confirmation array line format. Default to "%-25s | %-25s | %-25s" +=head3 log() + +String to insert in configuration log field (cfgLog) + =head2 run() The main method: it reads option, command and launch the corresponding From 2c86fdfffaa89606532d0a776b26bd17600c4d94 Mon Sep 17 00:00:00 2001 From: Xavier Date: Wed, 15 May 2019 06:11:27 +0200 Subject: [PATCH 17/19] Replace whoami by getpwuid (#1750) --- lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm index e54d00f70..d12ac4da9 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm @@ -250,7 +250,7 @@ sub _save { $saveParams->{cfgNum} = $self->cfgNum; $saveParams->{cfgNumFixed} = 1; } - $new->{cfgAuthor} = 'lmConfigEditor: ' . `whoami`; + $new->{cfgAuthor} = 'lmConfigEditor: ' . scalar( getpwuid $< ); chomp $new->{cfgAuthor}; $new->{cfgAuthorIP} = '127.0.0.1'; $new->{cfgDate} = time; From 2edb5517fd3e065f8f9053fdb9bc3ab1b3d91341 Mon Sep 17 00:00:00 2001 From: Xavier Date: Wed, 15 May 2019 06:49:33 +0200 Subject: [PATCH 18/19] Set a default log (#1750) --- lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm index d12ac4da9..ac875c372 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm @@ -255,7 +255,7 @@ sub _save { $new->{cfgAuthorIP} = '127.0.0.1'; $new->{cfgDate} = time; $new->{cfgVersion} = $Lemonldap::NG::Manager::VERSION; - $new->{cfgLog} = $self->log || ''; + $new->{cfgLog} = $self->log // 'Modified using LLNG cli'; $new->{key} ||= join( '', map { chr( int( ord( Crypt::URandom::urandom(1) ) * 94 / 256 ) + 33 ) } ( 1 .. 16 ) ); From 570513ab96e261fffcd72b557361008e85a78730 Mon Sep 17 00:00:00 2001 From: Xavier Guimard Date: Wed, 15 May 2019 13:40:27 +0200 Subject: [PATCH 19/19] Closes: #1750 --- lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm index ac875c372..366a446f2 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Cli.pm @@ -250,7 +250,7 @@ sub _save { $saveParams->{cfgNum} = $self->cfgNum; $saveParams->{cfgNumFixed} = 1; } - $new->{cfgAuthor} = 'lmConfigEditor: ' . scalar( getpwuid $< ); + $new->{cfgAuthor} = scalar( getpwuid $< ) . '(command-line)'; chomp $new->{cfgAuthor}; $new->{cfgAuthorIP} = '127.0.0.1'; $new->{cfgDate} = time;