package Lemonldap::NG::Portal::UserDB::LDAP; use strict; use Mouse; use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_LDAPCONNECTFAILED PE_LDAPERROR PE_BADCREDENTIALS); use Lemonldap::NG::Portal::Lib::LDAP; extends 'Lemonldap::NG::Common::Module'; our $VERSION = '2.0.0'; # PROPERTIES has ldap => ( is => 'rw', lazy => 1, builder => 'newLdap', ); sub newLdap { my $self = $_[0]; my $ldap; # Build object and test LDAP connexion if ( $ldap = Lemonldap::NG::Portal::Lib::LDAP->new( { p => $self->{p}, conf => $self->{conf} } ) and my $msg = $ldap->bind ) { if ( $msg->code != 0 ) { $self->lmLog( "LDAP error: " . $msg->error, 'error' ); } else { if ( $self->{conf}->{ldapPpolicyControl} and not $ldap->loadPP() ) { $self->lmLog( "LDAP password policy error", 'error' ); } } } else { $self->lmLog( "LDAP error: $@", 'error' ); } return $ldap; } has ldapGroupAttributeNameSearch => ( is => 'rw', builder => sub { return $_[0]->{conf}->{ldapGroupAttributeNameSearch} ? [ split( /\s+/, $_[0]->{conf}->{ldapGroupAttributeNameSearch} ), # Push group attribute value for recursive search ( $_[0]->{conf}->{ldapGroupRecursive} and $_[0]->{conf}->{ldapGroupAttributeNameGroup} ne "dn" ? $_[0]->{conf}->{ldapGroupAttributeNameGroup} : () ) ] : []; } ); has attrs => ( is => 'rw', builder => sub { return [ values %{ $_[0]->{conf}->{exportedVars} }, values %{ $_[0]->{conf}->{ldapExportedVars} } ]; } ); has filter => ( is => 'rw', lazy => 1, builder => 'buildFilter', ); sub buildFilter { my $conf = $_[0]->{conf}; $_[0]->{p}->lmLog( "LDAP Search base: $_[0]->{conf}->{ldapBase}", 'debug' ); # TODO : mailLDAPFilter my $filter = $conf->{AuthLDAPFilter} || $conf->{LDAPFilter} || '(&(uid=$user)(objectClass=inetOrgPerson))'; $filter =~ s/"/\\"/g; $filter =~ s/\$(\w+)/".\$req->{sessionInfo}->{$1}."/g; $filter =~ s/\$req->\{sessionInfo\}->\{user\}/\$req->{user}/g; $filter =~ s/\$req->\{sessionInfo\}->\{(_?password|mail)\}/\$req->{datas}->{$1}/g; $_[0]->{p}->lmLog( "LDAP transformed filter: $filter", 'debug' ); $filter = "sub{my(\$req)=\$_[0];return \"$filter\";}"; return eval $filter; } # INITIALIZATION sub init { my ($self) = @_; $self->ldap and $self->filter; } # Test LDAP connection before trying to bind sub bind { my $self = shift; unless ($self->ldap and $self->ldap->root_dse( attrs => ['supportedLDAPVersion'] ) ) { $self->ldap( $self->newLdap ); } return $self->ldap ? $self->ldap->bind(@_) : undef; } # RUNNING METHODS sub getUser { my ( $self, $req ) = @_; return PE_LDAPCONNECTFAILED unless $self->ldap and $self->bind(); my $mesg = $self->ldap->search( base => $self->conf->{ldapBase}, scope => 'sub', filter => $self->filter->($req), defer => $self->conf->{ldapSearchDeref} || 'find', attrs => $self->attrs, ); if ( $mesg->code() != 0 ) { $self->lmLog( 'LDAP Search error: ' . $mesg->error, 'error' ); return PE_LDAPERROR; } if ( $mesg->count() > 1 ) { $self->lmLog( 'More than one entry returned by LDAP directory', 'error' ); return PE_BADCREDENTIALS; } unless ( $req->datas->{entry} = $mesg->entry(0) ) { my $user = $req->{mail} || $req->{user}; $self->p->userError("$user was not found in LDAP directory"); return PE_BADCREDENTIALS; } $req->datas->{dn} = $req->datas->{entry}->dn(); PE_OK; } # Load all parameters included in exportedVars parameter. # Multi-value parameters are loaded in a single string with # a separator (param multiValuesSeparator) # @return Lemonldap::NG::Portal constant sub setSessionInfo { my ( $self, $req ) = @_; $req->{sessionInfo}->{dn} = $req->datas->{dn}; my %vars = ( %{ $self->conf->{exportedVars} }, %{ $self->conf->{ldapExportedVars} } ); while ( my ( $k, $v ) = each %vars ) { $self->{sessionInfo}->{$k} = $self->{ldap}->getLdapValue( $req->datas->{entry}, $v ) || ""; } PE_OK; } # Load all groups in $groups. # @return Lemonldap::NG::Portal constant sub setGroups { my ( $self, $req ) = @_; my $groups = $req->{sessionInfo}->{groups}; my $hGroups = $req->{sessionInfo}->{hGroups}; if ( $self->conf->{ldapGroupBase} ) { # Get value for group search my $group_value = $self->ldap->getLdapValue( $req->datas->{entry}, $self->conf->{ldapGroupAttributeNameUser} ); $self->lmLog( "Searching LDAP groups in " . $self->{ldapGroupBase} . " for $group_value", 'debug' ); # Call searchGroups my $ldapGroups = $self->ldap->searchGroups( $self->conf->{ldapGroupBase}, $self->conf->{ldapGroupAttributeName}, $group_value, $self->ldapGroupAttributeNameSearch ); foreach ( keys %$ldapGroups ) { my $groupName = $_; $hGroups->{$groupName} = $ldapGroups->{$groupName}; my $groupValues = []; foreach ( @{ $self->ldapGroupAttributeNameSearch } ) { next if $_ =~ /^name$/; my $firstValue = $ldapGroups->{$groupName}->{$_}->[0]; push @$groupValues, $firstValue; } $groups .= $self->conf->{multiValuesSeparator} . join( '|', @$groupValues ); } } $self->{sessionInfo}->{groups} = $groups; PE_OK; } 1;