From b54c95ccd2ca3380217d9b1b9e1696aed8ced35e Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Wed, 21 Apr 2021 22:14:47 +0200 Subject: [PATCH 1/8] Improve unit tests & Fix regex (#2509) --- .../lib/Lemonldap/NG/Portal/Password/Base.pm | 2 +- .../t/02-Password-Demo-Local-Ppolicy.t | 4 +- .../02-Password-Demo-Local-SpeChars-Ppolicy.t | 96 +++++++++++++++++++ .../t/02-Password-Demo-Local-noPpolicy.t | 8 +- 4 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 lemonldap-ng-portal/t/02-Password-Demo-Local-SpeChars-Ppolicy.t diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Password/Base.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Password/Base.pm index 928329c67..e7b7f752e 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Password/Base.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Password/Base.pm @@ -176,7 +176,7 @@ sub checkPasswordQuality { ## Min special characters # Just number of special characters must be checked if ( $self->conf->{passwordPolicyMinSpeChar} && $speChars eq '__ALL__' ) { - my $spe = $password =~ s/\w//g; + my $spe = $password =~ s/\W//g; if ( $spe < $self->conf->{passwordPolicyMinSpeChar} ) { $self->logger->error("Password has not enough special characters"); return PE_PP_INSUFFICIENT_PASSWORD_QUALITY; diff --git a/lemonldap-ng-portal/t/02-Password-Demo-Local-Ppolicy.t b/lemonldap-ng-portal/t/02-Password-Demo-Local-Ppolicy.t index b67990bed..d0e4961ab 100644 --- a/lemonldap-ng-portal/t/02-Password-Demo-Local-Ppolicy.t +++ b/lemonldap-ng-portal/t/02-Password-Demo-Local-Ppolicy.t @@ -9,7 +9,7 @@ use Lemonldap::NG::Portal::Main::Constants qw( require 't/test-lib.pm'; -my $res; +my ($res, $json); my $client = LLNG::Manager::Test->new( { ini => { @@ -56,7 +56,7 @@ ok( 'Password min size not respected' ); expectBadRequest($res); -my $json; + ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' ) or print STDERR "$@\n" . Dumper($res); ok( diff --git a/lemonldap-ng-portal/t/02-Password-Demo-Local-SpeChars-Ppolicy.t b/lemonldap-ng-portal/t/02-Password-Demo-Local-SpeChars-Ppolicy.t new file mode 100644 index 000000000..f43f4b070 --- /dev/null +++ b/lemonldap-ng-portal/t/02-Password-Demo-Local-SpeChars-Ppolicy.t @@ -0,0 +1,96 @@ +use Test::More; +use strict; +use IO::String; +use JSON; +use Lemonldap::NG::Portal::Main::Constants + 'PE_PP_INSUFFICIENT_PASSWORD_QUALITY'; + +require 't/test-lib.pm'; + +my ( $res, $json ); + +my $client = LLNG::Manager::Test->new( { + ini => { + logLevel => 'error', + passwordDB => 'Demo', + portalRequireOldPassword => 1, + passwordPolicyMinSize => 0, + passwordPolicyMinLower => 0, + passwordPolicyMinUpper => 0, + passwordPolicyMinDigit => 0, + passwordPolicyMinSpeChar => 2, + passwordPolicySpecialChar => '__ALL__', + portalDisplayPasswordPolicy => 1 + } + } +); + +# Try to authenticate +# ------------------- +ok( + $res = $client->_post( + '/', + IO::String->new('user=dwho&password=dwho'), + length => 23 + ), + 'Auth query' +); +count(1); +expectOK($res); +my $id = expectCookie($res); + +ok( + $res = + $client->_get( '/', cookie => "lemonldap=$id", accept => 'text/html' ), + 'Get Menu' +); +ok( $res->[2]->[0] =~ m%[2]->[0] ); +ok( + $res->[2]->[0] =~ +m%Minimal special characters: 2%, + ' passwordPolicyMinSpeChar' +) or print STDERR Dumper( $res->[2]->[0] ); +count(3); + +my $query = 'oldpassword=dwho&newpassword=@test&confirmpassword=@test'; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + cookie => "lemonldap=$id", + accept => 'application/json', + length => length($query) + ), + 'Password min special char policy not respected' +); +expectBadRequest($res); +ok( $json = eval { from_json( $res->[2]->[0] ) }, 'Response is JSON' ) + or print STDERR "$@\n" . Dumper($res); +ok( + $json->{error} == PE_PP_INSUFFICIENT_PASSWORD_QUALITY, + 'Response is PE_PP_INSUFFICIENT_PASSWORD_QUALITY' +) or explain( $json, "error => 28" ); +count(3); + +$query = 'oldpassword=dwho&newpassword=@%&confirmpassword=@%'; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + cookie => "lemonldap=$id", + accept => 'application/json', + length => length($query) + ), + 'Password min special char respected' +); +expectOK($res); +count(1); + +# Test $client->logout +$client->logout($id); + +clean_sessions(); + +done_testing( count() ); diff --git a/lemonldap-ng-portal/t/02-Password-Demo-Local-noPpolicy.t b/lemonldap-ng-portal/t/02-Password-Demo-Local-noPpolicy.t index b8a04281e..b6e82eb44 100644 --- a/lemonldap-ng-portal/t/02-Password-Demo-Local-noPpolicy.t +++ b/lemonldap-ng-portal/t/02-Password-Demo-Local-noPpolicy.t @@ -19,8 +19,8 @@ my $client = LLNG::Manager::Test->new( { passwordPolicyMinLower => 0, passwordPolicyMinUpper => 0, passwordPolicyMinDigit => 0, - passwordPolicyMinSpeChar => 2, - passwordPolicySpecialChar => '', + passwordPolicyMinSpeChar => 0, + passwordPolicySpecialChar => '__ALL__', portalDisplayPasswordPolicy => 1 } } @@ -48,8 +48,8 @@ ok( ok( $res->[2]->[0] =~ m%[2]->[0] ); -ok( $res->[2]->[0] =~ m%Minimal special characters: 2%, - ' passwordPolicyMinSpeChar' ) +ok( $res->[2]->[0] =~ m%%, + ' passwordPolicyNone' ) or print STDERR Dumper( $res->[2]->[0] ); count(3); From 82620525ba070c9cb341bf6decc05af892d1d7d1 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Thu, 22 Apr 2021 12:09:00 +0200 Subject: [PATCH 2/8] Documentation for Mobilizon --- doc/sources/admin/applications.rst | 2 + doc/sources/admin/applications/mobilizon.rst | 51 ++++++++++++++++++ .../admin/applications/mobilizon_logo.jpg | Bin 0 -> 9716 bytes 3 files changed, 53 insertions(+) create mode 100644 doc/sources/admin/applications/mobilizon.rst create mode 100644 doc/sources/admin/applications/mobilizon_logo.jpg diff --git a/doc/sources/admin/applications.rst b/doc/sources/admin/applications.rst index 509869c9c..1f929fabe 100644 --- a/doc/sources/admin/applications.rst +++ b/doc/sources/admin/applications.rst @@ -30,6 +30,7 @@ Applications applications/limesurvey applications/mattermost applications/mediawiki + applications/mobilizon applications/nextcloud applications/obm applications/office365 @@ -108,6 +109,7 @@ Application Configuration .. image:: applications/limesurvey_logo.png :doc:`LimeSurvey` ✔ .. image:: applications/mattermost_logo.png :doc:`Mattermost` ✔ .. image:: applications/mediawiki_logo.png :doc:`Mediawiki` ✔ +.. image:: applications/mobilizon_logo.jpg :doc:`Mobilizon` ✔ .. image:: applications/nextcloud-logo.png :doc:`NextCloud` ✔ .. image:: applications/obm_logo.png :doc:`OBM` ✔ .. image:: applications/logo_office_365.png :doc:`Office 365` ✔ diff --git a/doc/sources/admin/applications/mobilizon.rst b/doc/sources/admin/applications/mobilizon.rst new file mode 100644 index 000000000..ac4d0f779 --- /dev/null +++ b/doc/sources/admin/applications/mobilizon.rst @@ -0,0 +1,51 @@ +Mobilizon +========= + +|mobilizon_logo.jpg| + +Presentation +------------ + +`Mobilizon `__ is an online tool to help manage your events, your profiles and your groups. + +Mobilizon lets users `authenticate with OpenID Connect `__ through the same plugin used by Keycloak. + +First, make sure you have set up LemonLDAP::NG 's +:doc:`OpenID Connect service<..//openidconnectservice>` and added +:doc:`a Relaying Party for your Mobilizon instance<..//idpopenidconnect>` + +The only options you need to configure are: + +* *Client ID*: choose one +* *Client Secret*: choose one +* *Allowed redirection addresses for login*: ``https://mobilizon.example.com/auth/keycloak/callback`` + +Mobilizon configuration +----------------------- + +Edit ``/etc/mobilizon/config.exs``, and adjust the Client ID, Client Secret and URLs to match your domain :: + + config :ueberauth, + Ueberauth, + providers: [ + keycloak: {Ueberauth.Strategy.Keycloak, [default_scope: "openid profile email"]} + ] + + config :mobilizon, :auth, + oauth_consumer_strategies: [ + {:keycloak, "LemonLDAP::NG"} + ] + + config :ueberauth, Ueberauth.Strategy.Keycloak.OAuth, + client_id: "CHANGEME", + client_secret: "CHANGEME", + site: "https://auth.example.com", + authorize_url: "https://auth.example.com/oauth2/authorize", + token_url: "https://auth.example.com/oauth2/token", + userinfo_url: "https://auth.example.com/oauth2/userinfo", + token_method: :post + + +.. |mobilizon_logo.jpg| image:: /applications/mobilizon_logo.jpg + :class: align-center + diff --git a/doc/sources/admin/applications/mobilizon_logo.jpg b/doc/sources/admin/applications/mobilizon_logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4778a9caf54d51182ed71d356726ef8888bcc5f GIT binary patch literal 9716 zcmb7pWl&r})9&K#790WuSTtC0S#)t07Ka2$f&_OBfdvA=J-E9Ew-8)|F7D1^!5uE| zCw1@N+h?Zs+zjF&M;$SA02=tKZU4C1#kBwA*eq_6p$$Uxt6nD}KO=FYKL zfpIl|$eDw>CME^7EnIT*x?f;uUbsL*`hT?mkY7+RP>?WRdc}xdl)S)VqQ6xC(eXmu z%O?>U<6CrM87-36W=`L7Y9>heV*jlFgD`ywCVHk1NfzWIi;6&R_UlsY#Olc9Co21|)^cSF(Dw<}wcrq!I zFb;ygzBZwKLXIKOih2}GoHkDsCg);S`%CQ5I_H8olT`jY4pJtZ}msN@{#@&(`9}CmMGJz7Q+9BI7S|N;S&@XslaPd z!!#!i8D2(qBWBmrjJ|ci6(XT(u?GktE`w z!jXK|SyzrH zlTTuPYOMnNQ4B%rDVMsc#72EP&hPGW`$;^l)i=;6)zlS3SpX?#F)_MbZT%_d8cqj6 zrJv}-bk^&Ub5T}=i3Xmw3JL>7lU$uW>6Fu#-7^$M%UU%m_}5z^$Lo$mwdcVSe`aQ3 z76NnWw4AJMP8iqW#WNEsDsK+@oz}F43gQLo7#+AHSp*aiZOtKD1qwT~>B^vL|Lmg+ z(MWq1$|?cHon`!!zboL00*`L2zT{ea!% z(Tc~;VIx6I^#&IFi%JfWBBqoYfp;;kU^V z@-a*_i+T)UO)4vLob=pfip8sAS~vK!4JtB* zUykwDd~WHMNm3tZM-IC9wvP^Be)WEE>D-grN7-fJxMGAbNy%~JY>Tpv)Bqx}Q42$} z?^yj3P4z=%T_tUnn*$`u@>_YQ(7L`#x#lwjSW_T$RX$MAJ(L1hs$*FQFwF*ANm_JX5ssCEfRhap>xoelFhUW$W zi%LaaToR=JhR(VQQj*FJv3}ygrz{Z0go60b0TSul{@1 zb>fIkm%+*DC(ZD!DHooYx356*&9ND_;oRoj0Rc$GwEDb)LZJN5Ot5w?%4Ag@CRY$e%&w;RZN)BVkRGeZeoB4i2e zta+8*n_KilRT7503;t1D=Oq`$*ysp(&yE6lX3{v!B|=AqxSdesS)9OjYlbBb!OzQa z_KV(Vf7HHqm3J$JYN4F8#QrM*A17vi)yXgy{!4CUvx-(b?H+WL``av0wIl%JYf%5P zd{a=j@GOj7a1r<_Sno$7lpS+#?f8J{QEIk)X6#6IFMYu~&+~?k>%p7tP#a@~)J|46vc}~-jG}JIq(JV&dRLX}fqCU72R6uQ$(G%$3A<zg}LFR<>jHd?rj82ho!OtvnwTy8eA34>K(7PG?zJm+kft8?TI%Wg@WOcZgbR* zUwxc)k|0WmSan6iD}^H6X~X{3UZgMDbJnoWzGwIjxAlR_*Wg+AO6Eu1Utr8H_*Tbv z40gjfhozSwhF2=Yx`a}pA{tu?jp3M5yZoH|If5oaE=;lw!SJrQW zNFsAQra4s#liz2HtdA9dRSr*TPtO@mts!9Wh3Ga1Y6O>iuy;$Ng~>mM1BH0Uarh{9 z1sOqoX7RvHj2|Q$;wJ-#D3FWS{ZrOhc=@*n<8B~R1zyq>-o;U=)?h1>Md=y(!q%lP zyT4)F-R)->eL=aw^9grT1-GKNM4jHWpr2aIL*kta?g|2_^P!~Ja2(-CM$@1x%R67m zAa(XK1bao3{fgqDr#DLw%}*t9&ztj0=<9ZwVk0tZ(xC^%9QE)@Jp(skrrBw_o-b~8 z`DNjS5?7v4Ox1;PJ$s|kv#H}#1%rgb?C$mUCV?z!C)mk`(mz-%4=2x)(w`8gHzcJ| zv+ISqF*>|%d1Kw-$z8w*=VOxC%ZI!~UFv^3K5z;DeVxEs?D!oahNyi>lfK&IfVHaF zr1l2)&_Oxi1ty&8(6(>6qGr%@o{N&m|VZ2(Xxj%(&=yg3} zE_xz$W z_^@N&4>IMzJ3^WhwNBo>7Nm)8e4RE*6mj6_%AVjhH7g)Ys37l*8su1R7wt)1I2I

6OZo2>UMNTK`@Q4jXvBq_pRMCu+y`SPo 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 ReC-DRyZ!!)r1#JB{|A40ZioN? literal 0 HcmV?d00001 From 5ba0c11b58c68f8930b9c5bb8d3fc3fe500da964 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Thu, 22 Apr 2021 17:47:50 +0200 Subject: [PATCH 3/8] Add helper to build CSP host list (#2513) --- .../lib/Lemonldap/NG/Portal/Main/Run.pm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index 5474826a0..ef6309d59 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -15,6 +15,7 @@ package Lemonldap::NG::Portal::Main; use strict; use URI::Escape; +use URI; use JSON; use Lemonldap::NG::Common::Util qw(getPSessionID); @@ -1198,4 +1199,16 @@ sub loadTemplate { return $tpl->output; } +# This method extracts the scheme://host:port part of a URL for use in +# Content-Security-Polity header +sub cspGetHost { + my ( $self, $url ) = @_; + my $uri = $url // ""; + unless ( $uri->isa("URI") ) { + $uri = URI->new($uri); + } + return ( + $uri->scheme . "://" . ( $uri->_port ? $uri->host_port : $uri->host ) ); +} + 1; From 913ebbd556ec3ba50d68d3c435bc5ac5915eb9de Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Thu, 22 Apr 2021 17:42:19 +0200 Subject: [PATCH 4/8] fix missing domain in child-src during SAML POST logout (#2513) --- lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm | 2 ++ lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm index 937df07a7..fefc62cd4 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SAML.pm @@ -2675,6 +2675,8 @@ sub sendLogoutRequestToProvider { name => $providerName, } ); + $req->data->{cspChildSrc}->{ $self->p->cspGetHost( $logout->msg_url ) } + = 1; } # HTTP-SOAP diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index ef6309d59..3c7a86f76 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -936,6 +936,11 @@ sub sendHtml { @url = map { s#https?://([^/]+).*#$1#; $_ } ( $req->info =~ /data->{cspChildSrc} ) eq "HASH" ) { + push @url, keys %{ $req->data->{cspChildSrc} }; + } if (@url) { $csp .= join( ' ', 'child-src', @url, "'self'" ) . ';'; } From a876d978afaa6754b7cf2be075b67cc274aec58c Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Thu, 22 Apr 2021 18:23:43 +0200 Subject: [PATCH 5/8] Suggest improvement for next major version --- lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index 3c7a86f76..b6e4d2a22 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -931,6 +931,8 @@ sub sendHtml { } # Check if frames need to be embedded + # FIXME: we should use $req->data->{cspChildSrc} anywhere an iframe is + # created in the code, and remove this my @url; if ( $req->info ) { @url = map { s#https?://([^/]+).*#$1#; $_ } From cd97d3b9227f16f0edcdd30b43a7dfe80f1c56f6 Mon Sep 17 00:00:00 2001 From: Maxime Besson Date: Thu, 22 Apr 2021 17:48:18 +0200 Subject: [PATCH 6/8] Refactor $req->{cspFormAction} (#2513) --- .../lib/Lemonldap/NG/Portal/Lib/Choice.pm | 14 +++++++------- .../lib/Lemonldap/NG/Portal/Main/Run.pm | 14 +++++++++----- lemonldap-ng-portal/t/28-AuthChoice-with-rules.t | 4 ++-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/Choice.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/Choice.pm index da389e5d8..d5201fece 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/Choice.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/Choice.pm @@ -12,7 +12,7 @@ our $VERSION = '2.0.11'; has modules => ( is => 'rw', default => sub { {} } ); has rules => ( is => 'rw', default => sub { {} } ); has type => ( is => 'rw' ); -has catch => ( is => 'rw', default => sub { {} } ); +has catch => ( is => 'rw', default => sub { {} } ); has sessionKey => ( is => 'ro', default => '_choice' ); my $_choiceRules; @@ -116,8 +116,10 @@ sub checkChoice { } unless ($name) { + # Set by OAuth Resource Owner grant // RESTServer pwdCheck - if ($req->data->{_pwdCheck} and $self->{conf}->{authChoiceAuthBasic}) { + if ( $req->data->{_pwdCheck} and $self->{conf}->{authChoiceAuthBasic} ) + { $name = $self->{conf}->{authChoiceAuthBasic}; } } @@ -213,7 +215,7 @@ sub _buildAuthLoop { if ( $auth and $userDB and $passwordDB ) { # Default URL - $req->{cspFormAction} ||= ''; + $req->data->{cspFormAction} ||= {}; if ( defined $url and not $self->checkXSSAttack( 'URI', @@ -222,11 +224,9 @@ sub _buildAuthLoop { q%^(https?://)?[^\s/.?#$].[^\s]+$% # URL must be well formatted ) { - #$url .= $req->env->{'REQUEST_URI'}; - # Avoid append same URL - $req->{cspFormAction} .= " $url" - unless $req->{cspFormAction} =~ qr%\b$url\b%; + my $csp_uri = $self->cspGetHost($url); + $req->data->{cspFormAction}->{$csp_uri} = 1; } else { $url .= '#'; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm index b6e4d2a22..4b574bc39 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Run.pm @@ -898,10 +898,14 @@ sub sendHtml { $csp .= " $url"; } } - if ( defined $req->{cspFormAction} ) { - $self->logger->debug( - "Set CSP form-action with request URL: " . $req->{cspFormAction} ); - $csp .= " " . $req->{cspFormAction}; + if ( defined $req->data->{cspFormAction} + and ref( $req->data->{cspFormAction} ) eq "HASH" ) + { + my $request_csp_form_action = + join( " ", keys %{ $req->data->{cspFormAction} } ); + $self->logger->debug( "Set CSP form-action with request URL: " + . $request_csp_form_action ); + $csp .= " " . $request_csp_form_action; } # Set SAML Discovery Protocol in form-action @@ -1083,7 +1087,7 @@ sub registerLogin { } my $history = $req->sessionInfo->{_loginHistory} ||= {}; - my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login'; + my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login'; $history->{$type} ||= []; $self->logger->debug("Current login saved into $type"); diff --git a/lemonldap-ng-portal/t/28-AuthChoice-with-rules.t b/lemonldap-ng-portal/t/28-AuthChoice-with-rules.t index e3877bbef..7e611ce05 100644 --- a/lemonldap-ng-portal/t/28-AuthChoice-with-rules.t +++ b/lemonldap-ng-portal/t/28-AuthChoice-with-rules.t @@ -114,9 +114,9 @@ m%