Package: release.debian.org Severity: normal Tags: bullseye User: release.debian....@packages.debian.org Usertags: pu
[ Reason ] lemonldap-ng is vulnerable to password bypass (impact critical) in a very unlikely setup (probability very low). CVE-2021-40874 [ Impact ] In such configuration, a remote lemonldap-ng system that queries the main lemonldap-ng system using internal lemonldap-ng protocol instead of SAML/OpenID-Connect, accepts user with _wrong password; if and only if_ main lemonldap-ng system is configured to use both Kerberos and LDAP authentication. [ Tests ] Tests passed and upstream patch adds a new test [ Risks ] Low risk, test coverage proves that package isn't broken with such change (trivial for a lemonldap-ng dev ;-)) [ Checklist ] [X] *all* changes are documented in the d/changelog [X] I reviewed all changes and I approve them [X] attach debdiff against the package in (old)stable [X] the issue is verified as fixed in unstable [ Changes ] Instead of setting login/password into result variables ($req->user), RESTServer stores them in form and launch the whole authentication process ($self->p->authProcess) instead of selected steps. Same change is applied to CheckState plugin (no major risk here, this plugin is reserved to LLNG administrators). Cheers, Yadd
diff --git a/debian/changelog b/debian/changelog index a56d54279..f6be653a8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +lemonldap-ng (2.0.11+ds-4+deb11u1) bullseye; urgency=medium + + * Fix auth process in password-testing plugins (Closes: CVE-2021-20874) + + -- Yadd <y...@debian.org> Thu, 24 Feb 2022 15:16:09 +0100 + lemonldap-ng (2.0.11+ds-4) unstable; urgency=high * Import security fixes from 2.0.12 diff --git a/debian/patches/CVE-2021-40874.patch b/debian/patches/CVE-2021-40874.patch new file mode 100644 index 000000000..a333d3260 --- /dev/null +++ b/debian/patches/CVE-2021-40874.patch @@ -0,0 +1,238 @@ +Description: Fix auth process in password-testing plugins (#2611) +Author: Maxime Besson <maxime.bes...@worteks.com> +Origin: upstream, https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/-/commit/66946e8 +Bug: https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/-/issues/2612 +Forwarded: not-needed +Reviewed-By: Yadd <y...@debian.org> +Last-Update: 2022-01-14 + +--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/_WebForm.pm ++++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/_WebForm.pm +@@ -73,7 +73,10 @@ + my $res = PE_OK; + + # 1. No user defined at all -> first access +- unless ( $defUser and $req->method =~ /^POST$/i ) { ++ # _pwdCheck is a workaround to make CheckUser work while using a GET ++ unless ( $defUser ++ and ( uc( $req->method ) eq "POST" or $req->data->{_pwdCheck} ) ) ++ { + $res = PE_FIRSTACCESS; + } + +@@ -170,6 +173,7 @@ + + sub setSecurity { + my ( $self, $req ) = @_; ++ return if $req->data->{skipToken}; + + # If captcha is enable, prepare it + if ( $self->captcha ) { +--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckState.pm ++++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckState.pm +@@ -41,16 +41,22 @@ + + if ( my $user = $req->param('user') and my $pwd = $req->param('password') ) + { +- $req->user($user); +- $req->data->{password} = $pwd; ++ $req->parameters->{user} = ($user); ++ $req->parameters->{password} = $pwd; ++ $req->data->{skipToken} = 1; ++ ++ # This makes Auth::Choice use authChoiceAuthBasic if defined ++ $req->data->{_pwdCheck} = 1; + + # Not launched methods: +- # - "extractFormInfo" due to "token" + # - "buildCookie" useless here + $req->steps( [ +- 'getUser', 'authenticate', +- @{ $self->p->betweenAuthAndData }, $self->p->sessionData, +- @{ $self->p->afterData }, 'storeHistory', ++ @{ $self->p->beforeAuth }, ++ $self->p->authProcess, ++ @{ $self->p->betweenAuthAndData }, ++ $self->p->sessionData, ++ @{ $self->p->afterData }, ++ 'storeHistory', + @{ $self->p->endAuth } + ] + ); +--- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm ++++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm +@@ -681,11 +681,13 @@ + 400 ); + } + +- $req->user($user); +- $req->data->{password} = $password; ++ $req->parameters->{user} = $user; ++ $req->parameters->{password} = $password; ++ $req->data->{_pwdCheck} = 1; ++ $req->data->{skipToken} = 1; + + if ( $self->p->_userDB ) { +- $req->steps( [ 'getUser', 'authenticate' ] ); ++ $req->steps( [ $self->p->authProcess ] ); + my $result = $self->p->process($req); + if ( $result == PE_PASSWORD_OK or $result == PE_OK ) { + return $self->p->sendJSONresponse( $req, +--- /dev/null ++++ b/lemonldap-ng-portal/t/35-REST-auth-password-server.t +@@ -0,0 +1,126 @@ ++use Test::More; ++use strict; ++use IO::String; ++use MIME::Base64; ++use JSON; ++ ++require 't/test-lib.pm'; ++ ++my $res; ++ ++my $client = LLNG::Manager::Test->new( { ++ ini => { ++ logLevel => 'error', ++ useSafeJail => 1, ++ requireToken => 1, ++ restAuthServer => 1, ++ restPasswordServer => 1, ++ authentication => 'Combination', ++ userDB => 'Same', ++ ++ combination => '[K,Dm] or [Dm]', ++ combModules => { ++ K => { ++ for => 1, ++ type => 'Kerberos', ++ }, ++ Dm => { ++ for => 0, ++ type => 'Demo', ++ }, ++ }, ++ krbKeytab => '/etc/keytab', ++ krbByJs => 1, ++ } ++ } ++); ++ ++# Test pwdConfirm endpoint ++ ++my $res = expectJSON( ++ postJSON( ++ $client, ++ "/proxy/pwdConfirm", ++ { ++ user => "dwho", ++ password => "dwho", ++ } ++ ) ++); ++ ++is( $res->{result}, 1, "Correct password is accepted" ); ++count(1); ++ ++my $res = expectJSON( ++ postJSON( ++ $client, ++ "/proxy/pwdConfirm", ++ { ++ user => "waldo", ++ password => "dwho", ++ } ++ ) ++); ++ ++is( $res->{result}, 0, "Incorrect user is rejected" ); ++count(1); ++ ++my $res = expectJSON( ++ postJSON( ++ $client, ++ "/proxy/pwdConfirm", ++ { ++ user => "dwho", ++ password => "wrongpass", ++ } ++ ) ++); ++ ++is( $res->{result}, 0, "Incorrect password is rejected" ); ++count(1); ++ ++# Test getUser endpoint ++# Existing user ++my $res = expectJSON( ++ postJSON( ++ $client, ++ "/proxy/getUser", ++ { ++ user => "dwho", ++ } ++ ) ++); ++is( $res->{result}, 1, "Correct result" ); ++is( $res->{info}->{cn}, "Doctor Who", "Correct attributes" ); ++is( $res->{info}->{_whatToTrace}, "dwho", "Correct macro" ); ++count(3); ++ ++# Missing user ++my $res = expectJSON( ++ postJSON( ++ $client, ++ "/proxy/getUser", ++ { ++ user => "notfound", ++ } ++ ) ++); ++is( $res->{result}, 0, "Correct result" ); ++is( $res->{info}, undef, "No attributes" ); ++count(2); ++ ++clean_sessions(); ++ ++done_testing( count() ); ++ ++sub postJSON { ++ my ( $portal, $url, $payload ) = @_; ++ my $string_payload = to_json($payload); ++ return $portal->_post( ++ $url, ++ IO::String->new($string_payload), ++ accept => 'application/json', ++ type => 'application/json', ++ length => length($string_payload) ++ ); ++} +--- a/lemonldap-ng-portal/t/65-CheckState.t ++++ b/lemonldap-ng-portal/t/65-CheckState.t +@@ -8,10 +8,25 @@ + my $client = LLNG::Manager::Test->new( { + ini => { + logLevel => 'error', +- authentication => 'Demo', ++ requireToken => 1, + checkStateSecret => 'x', + checkState => 1, ++ authentication => 'Combination', + userDB => 'Same', ++ ++ combination => '[K,Dm] or [Dm]', ++ combModules => { ++ K => { ++ for => 1, ++ type => 'Kerberos', ++ }, ++ Dm => { ++ for => 0, ++ type => 'Demo', ++ }, ++ }, ++ krbKeytab => '/etc/keytab', ++ krbByJs => 1, + } + } + ); diff --git a/debian/patches/series b/debian/patches/series index a1245fc76..644277be7 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -8,3 +8,4 @@ fix-trusted-domain-wildcard.patch fix-trusted-domain-regex.patch fix-xss-on-register-form.patch dont-display-totp-secret.patch +CVE-2021-40874.patch