2016-05-05 22:26:41 +02:00
|
|
|
package Lemonldap::NG::Portal::Lib::LDAP;
|
2016-04-20 07:09:23 +02:00
|
|
|
|
|
|
|
use strict;
|
2017-01-15 14:18:01 +01:00
|
|
|
use Mouse;
|
|
|
|
use Lemonldap::NG::Portal::Lib::Net::LDAP;
|
2019-06-17 21:14:37 +02:00
|
|
|
use Lemonldap::NG::Portal::Main::Constants
|
|
|
|
qw(PE_OK PE_LDAPCONNECTFAILED PE_LDAPERROR PE_BADCREDENTIALS);
|
2016-04-20 07:09:23 +02:00
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
extends 'Lemonldap::NG::Common::Module';
|
2016-04-20 07:09:23 +02:00
|
|
|
|
2019-09-12 21:56:49 +02:00
|
|
|
our $VERSION = '2.0.6';
|
2016-04-20 07:09:23 +02:00
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
# PROPERTIES
|
2016-04-20 07:09:23 +02:00
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
has ldap => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
builder => 'newLdap',
|
|
|
|
);
|
2016-04-20 07:09:23 +02:00
|
|
|
|
2019-06-17 21:14:37 +02:00
|
|
|
has attrs => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
builder => sub {
|
|
|
|
return [
|
|
|
|
values %{ $_[0]->{conf}->{exportedVars} },
|
|
|
|
values %{ $_[0]->{conf}->{ldapExportedVars} }
|
|
|
|
];
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
sub newLdap {
|
|
|
|
my $self = $_[0];
|
|
|
|
my $ldap;
|
2016-04-20 07:09:23 +02:00
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
# Build object and test LDAP connexion
|
2018-09-04 07:08:46 +02:00
|
|
|
unless (
|
2017-01-15 14:18:01 +01:00
|
|
|
$ldap = Lemonldap::NG::Portal::Lib::Net::LDAP->new(
|
|
|
|
{ p => $self->{p}, conf => $self->{conf} }
|
|
|
|
)
|
|
|
|
)
|
2016-04-20 07:09:23 +02:00
|
|
|
{
|
2018-09-04 09:39:21 +02:00
|
|
|
$self->logger->error("LDAP initialization error: $@");
|
2018-09-04 07:08:46 +02:00
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Test connection
|
|
|
|
my $msg = $ldap->bind;
|
|
|
|
if ( $msg->code ) {
|
|
|
|
$self->logger->error( 'LDAP test has failed: ' . $msg->error );
|
2016-04-20 07:09:23 +02:00
|
|
|
}
|
2018-09-04 07:08:46 +02:00
|
|
|
elsif ( $self->{conf}->{ldapPpolicyControl} and not $ldap->loadPP() ) {
|
|
|
|
$self->logger->error("LDAP password policy error");
|
2016-04-20 07:09:23 +02:00
|
|
|
}
|
2017-01-15 14:18:01 +01:00
|
|
|
return $ldap;
|
2016-04-20 07:09:23 +02:00
|
|
|
}
|
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
has filter => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
builder => 'buildFilter',
|
|
|
|
);
|
|
|
|
|
2018-01-22 21:57:48 +01:00
|
|
|
has mailFilter => (
|
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
builder => 'buildMailFilter',
|
|
|
|
);
|
|
|
|
|
2018-01-24 22:32:08 +01:00
|
|
|
sub buildFilter {
|
|
|
|
return $_[0]->_buildFilter( $_[0]->conf->{AuthLDAPFilter}
|
|
|
|
|| $_[0]->conf->{LDAPFilter}
|
|
|
|
|| '(&(uid=$user)(objectClass=inetOrgPerson))' );
|
|
|
|
}
|
|
|
|
|
2018-01-22 21:57:48 +01:00
|
|
|
sub buildMailFilter {
|
2018-01-24 22:32:08 +01:00
|
|
|
my $f = $_[0]->conf->{mailLDAPFilter}
|
|
|
|
|| '(&(mail=$user)(objectClass=inetOrgPerson))';
|
|
|
|
$f =~ s/\$mail\b/\$user/g;
|
|
|
|
return $_[0]->_buildFilter($f);
|
2018-01-22 21:57:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub _buildFilter {
|
2018-09-04 07:08:46 +02:00
|
|
|
my ( $self, $filter ) = @_;
|
|
|
|
my $conf = $self->{conf};
|
|
|
|
$self->{p}->logger->debug("LDAP Search base: $_[0]->{conf}->{ldapBase}");
|
2017-01-15 14:18:01 +01:00
|
|
|
$filter =~ s/"/\\"/g;
|
|
|
|
$filter =~ s/\$(\w+)/".\$req->{sessionInfo}->{$1}."/g;
|
|
|
|
$filter =~ s/\$req->\{sessionInfo\}->\{user\}/\$req->{user}/g;
|
|
|
|
$filter =~
|
2018-07-05 22:56:16 +02:00
|
|
|
s/\$req->\{sessionInfo\}->\{(_?password|mail)\}/\$req->{data}->{$1}/g;
|
2018-09-04 07:08:46 +02:00
|
|
|
$self->{p}->logger->debug("LDAP transformed filter: $filter");
|
2017-01-15 14:18:01 +01:00
|
|
|
$filter = "sub{my(\$req)=\$_[0];return \"$filter\";}";
|
2018-09-04 07:08:46 +02:00
|
|
|
my $res = eval $filter;
|
|
|
|
|
|
|
|
if ($@) {
|
|
|
|
$self->error("Unable to build fiter: $@");
|
|
|
|
}
|
|
|
|
return $res;
|
2016-04-20 07:09:23 +02:00
|
|
|
}
|
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
# INITIALIZATION
|
2016-04-20 07:09:23 +02:00
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
sub init {
|
|
|
|
my ($self) = @_;
|
2018-09-04 09:50:48 +02:00
|
|
|
$self->ldap
|
|
|
|
or $self->logger->error(
|
|
|
|
"LDAP initialization has failed, but let's continue");
|
2018-09-04 09:39:21 +02:00
|
|
|
$self->filter;
|
2017-01-15 14:18:01 +01:00
|
|
|
}
|
2017-02-15 07:41:50 +01:00
|
|
|
|
2017-01-15 14:18:01 +01:00
|
|
|
# RUNNING METHODS
|
2016-04-20 07:09:23 +02:00
|
|
|
|
2019-06-17 21:14:37 +02:00
|
|
|
sub getUser {
|
|
|
|
my ( $self, $req, %args ) = @_;
|
2019-10-01 19:17:31 +02:00
|
|
|
|
2019-11-20 16:52:04 +01:00
|
|
|
$self->validateLdap;
|
|
|
|
|
|
|
|
unless ( $self->ldap ) {
|
|
|
|
return PE_LDAPCONNECTFAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
$self->bind();
|
|
|
|
|
2019-06-17 21:14:37 +02:00
|
|
|
my $mesg = $self->ldap->search(
|
|
|
|
base => $self->conf->{ldapBase},
|
|
|
|
scope => 'sub',
|
|
|
|
filter => (
|
|
|
|
$args{useMail}
|
|
|
|
? $self->mailFilter->($req)
|
|
|
|
: $self->filter->($req)
|
|
|
|
),
|
|
|
|
defer => $self->conf->{ldapSearchDeref} || 'find',
|
|
|
|
attrs => $self->attrs,
|
|
|
|
);
|
|
|
|
if ( $mesg->code() != 0 ) {
|
2019-09-30 17:19:57 +02:00
|
|
|
$self->logger->error(
|
|
|
|
'LDAP Search error ' . $mesg->code . ": " . $mesg->error );
|
2019-06-17 21:14:37 +02:00
|
|
|
return PE_LDAPERROR;
|
|
|
|
}
|
|
|
|
if ( $mesg->count() > 1 ) {
|
|
|
|
$self->logger->error('More than one entry returned by LDAP directory');
|
|
|
|
eval { $self->p->_authentication->setSecurity($req) };
|
|
|
|
return PE_BADCREDENTIALS;
|
|
|
|
}
|
2019-08-06 21:54:41 +02:00
|
|
|
unless ( $req->data->{ldapentry} = $mesg->entry(0) ) {
|
2019-06-17 21:14:37 +02:00
|
|
|
$self->userLogger->warn("$req->{user} was not found in LDAP directory");
|
|
|
|
eval { $self->p->_authentication->setSecurity($req) };
|
|
|
|
return PE_BADCREDENTIALS;
|
|
|
|
}
|
2019-08-06 21:54:41 +02:00
|
|
|
$req->data->{dn} = $req->data->{ldapentry}->dn();
|
2019-06-17 21:14:37 +02:00
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2019-10-01 19:17:31 +02:00
|
|
|
# Validate LDAP connection before use
|
|
|
|
sub validateLdap {
|
|
|
|
my ($self) = @_;
|
2017-01-15 14:18:01 +01:00
|
|
|
unless ($self->ldap
|
|
|
|
and $self->ldap->root_dse( attrs => ['supportedLDAPVersion'] ) )
|
|
|
|
{
|
2018-03-13 14:43:12 +01:00
|
|
|
$self->ldap->DESTROY if ( $self->ldap );
|
2017-01-15 14:18:01 +01:00
|
|
|
$self->ldap( $self->newLdap );
|
|
|
|
}
|
2019-10-01 19:17:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Bind
|
|
|
|
sub bind {
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
$self->validateLdap;
|
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
return undef unless ( $self->ldap );
|
2017-01-15 14:18:01 +01:00
|
|
|
my $msg = $self->ldap->bind(@_);
|
|
|
|
if ( $msg->code ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error( $msg->error );
|
2017-01-15 14:18:01 +01:00
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
return 1;
|
2016-04-20 07:09:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|