Security Advisories (3)
CVE-2021-35472 (2021-07-30)

An issue was discovered in LemonLDAP::NG before 2.0.12. Session cache corruption can lead to authorization bypass or spoofing. By running a loop that makes many authentication attempts, an attacker might alternately be authenticated as one of two different users.

CVE-2021-35473

OAuth2 handler does not verify access token validity

CVE-2026-19349 (2026-08-16)

Lemonldap::NG::Portal versions from 2.0.0 before 2.16.9, from 2.17.0 before 2.21.5, from 2.22.0 before 2.23.3 for Perl allow authentication bypass via an OAuth2 state parameter stored as an SSO session in the GitHub and LinkedIn backends. Before redirecting to the identity provider, extractFormInfo() creates the state session with the positional call `getApacheSession( undef, 1, 0, 'GitHubState' )`. getApacheSession() takes a session id followed by a named argument hash, so the trailing arguments become that hash, `kind` defaults to SSO, and the state is written to the global session storage as a regular SSO session. Its identifier is handed to the unauthenticated visitor as the state parameter of the redirection URL. Any visitor who reaches the GitHub or LinkedIn endpoint can replay that identifier as a session cookie and obtain a valid SSO session without authenticating. The session holds neither _user nor authenticationLevel, which the shipped bootstrap configuration accepts because it grants virtual hosts a "default => accept" access rule; deployments whose rules test the user or require an authentication level are less exposed. Only configurations with the GitHub or LinkedIn authentication module enabled are affected.

NAME

Lemonldap::NG::Portal::Main::Plugin - Base class for Lemonldap::NG::Portal modules (plugins, authentication modules,...).

SYNOPSIS

package Lemonldap::NG::Portal::My::Plugin;
use Mouse;
extends 'Lemonldap::NG::Portal::Main::Plugin';

use constant beforeAuth => 'verifyIP';

sub init {
    my ($self) = @_;
    $self->addUnauthRoute( mypath => 'hello', [ 'GET', 'PUT' ] );
    $self->addAuthRoute( mypath => 'welcome', [ 'GET', 'PUT' ] );
    return 1;
}
sub verifyIP {
    my ($self, $req) = @_;
    return PE_ERROR if($req->address !~ /^10/);
    return PE_OK;
}
sub hello {
    my ($self, $req) = @_;
    ...
    return $self->p->sendJSONresponse($req, { hello => 1 });
}
sub welcome {
    my ($self, $req) = @_;
    ...
    return $self->p->sendHtml($req, 'template', params => { WELCOME => 1 });
}

DESCRIPTION

Lemonldap::NG::Portal::Main::Plugin provides many methods to easily write Lemonldap::NG addons.

init() is called for each plugin. If a plugin initialization fails (init() returns 0), the portal responds a 500 status code for each request.

Writing plugins

Custom plugins can be inserted in portal by declaring them in lemonldap-ng.ini file, section [portal], key customPlugins:

[portal]
customPlugins = ::My::Plugin1, ::My::Plugin2

Plugins must be valid packages well found in @INC.

Plugin entry points

Entry point based on PATH_INFO

Plugins can declare unauthRoutes/authRoutes during initialization (= /path/info). Methods declared in this way must be declared in the plugin class. They will be called with $req argument. $req is the HTTP request. (See Lemonldap::NG::Portal::Main::Request). These methods must return a valid PSGI response. You can also use sendJSONresponse() or sendHtml() methods (see Lemonldap::NG::Common::PSGI).

Example:

sub init {
    my ($self) = @_;
    $self->addUnauthRoute( mypath => 'hello', [ 'GET', 'PUT' ] );
    $self->addAuthRoute( mypath => 'welcome', [ 'GET', 'PUT' ] );
    return 1;
}
sub hello {
    my ($self, $req) = @_;
    ...
    return $self->p->sendJSONresponse($req, { hello => 1 });
}
sub welcome {
    my ($self, $req) = @_;
    ...
    return $self->p->sendHtml($req, 'template', params => { WELLCOME => 1 });
}

If you want to get a "protected application" behavior, you can use addAuthRouteWithRedirect. This methods calls addAuthRoute with given arguments and build a "unAuth" route that build a redirection after authentication.

Entry point in auth process

A plugin which wants to be inserted in authentication process has to declare constants set with method name to run. Following entry points are available.

beforeAuth: method called before authentication process
betweenAuthAndData: method called after authentication and before setting sessionInfo provisionning
afterData: method called after sessionInfo provisionning (macros, groups,...)
authCancel: method called when user click on "cancel" during auth process
forAuthUser: method called for already authenticated users
beforeLogout: method called before logout

Note: methods inserted so must return a PE_* constant. See Lemonldap::NG::Portal::Main::Constants.

Advanced entry points

These entry points are not stored in $req->step but launched on the fly:

afterSub: hash ref that give methods to call after given main method is called. Example:
use constant afterSub => {
    getUser => 'mysub',
}
sub mysub {
    my ( $self ,$req ) = @_;
    # Do something
    return PE_OK;
}
aroundSub: hash ref that give methods to call instead of given main method. Example:
use constant aroundSub => {
    getUser => 'mysub',
};
sub mysub {
    my ( $self, $sub, $req ) = @_;
    # Do something before
    my $ret = $sub->($req);
    # Do something after
    return $ret;
}

Do not launch "getUser" but use the given $sub. This permits multiple plugins to use "aroundSub" in the same time.

hook: hash ref that gives methods to call when a hook is triggered in the LemonLDAP::NG code. Example:
use constant hook => {
    oidcGenerateIDToken          => 'addClaimToIDToken'
};

sub addClaimToIDToken {
  my ( $self, $req, $payload, $rp ) = @_;
  $payload->{"id_token_hook"} = 1;
  return PE_OK;
}

LOGGING

Logging is provided by $self->logger and $self->userLogger. The following rules must be applied:

logger->debug: technical debugging messages
logger->info: simple technical information
logger->notice: technical information that could interest administrators
logger->warn: technical warning
logger->error: error that must be reported to administrator
userLogger->info: simple information about user's action
userLogger->notice: information that may be registered (auth success,...)
userLogger->warn: bad action of a user (auth failure). Auth/Combination transform it to "info" when another authentication scheme is available
userLogger->error: bad action of a user that must be reported, (even if another backend is available with Combination)

SEE ALSO

http://lemonldap-ng.org

OTHER POD FILES

Writing an authentication module: Lemonldap::NG::Portal::Auth
Writing a UserDB module: Lemonldap::NG::Portal::UserDB
Writing a second factor module: Lemonldap::NG::Portal::Main::SecondFactor
Writing an issuer module: Lemonldap::NG::Portal::Main::Issuer
Writing another plugin: Lemonldap::NG::Portal::Main::Plugin
Request object: Lemonldap::NG::Portal::Main::Request
Adding parameters in the manager: Lemonldap::NG::Manager::Build

AUTHORS

LemonLDAP::NG team http://lemonldap-ng.org/team

BUG REPORT

Use OW2 system to report bug or ask for features: https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues

DOWNLOAD

Lemonldap::NG is available at http://forge.objectweb.org/project/showfiles.php?group_id=274

COPYRIGHT AND LICENSE

See COPYING file for details.

This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.