Commit 771935fa authored by Ira Snyder's avatar Ira Snyder

Improve LDAP User Authentication Support

LDAP servers often have their users grouped into nested hierarchies,
usually consisting of Organizational Units (OU). This commit extends the
LDAP support so that it can locate the correct user in a server with a
nested hierarchy.

Different LDAP server schemas often use a different attribute for the
username. For example, Microsoft Active Directory commonly uses the
"sAMAccountName" as a username, while many other LDAP servers commonly
use the "uid" attribute as a username. This commit extends the LDAP
support so that the user can choose which attribute to use in the
configuration file, using the "user_attr" configuration setting.

With both of these changes in place, it now makes sense to merge the
configuration settings "bind_user" and "bind_dn" together into the
single configuration setting "bind_dn". The configuration settings now
match my expectations as an experienced LDAP administrator.

The configuration template has been updated to match these changes. In
addition, the LDAP section in the configuration template has improved
comments to explain the meaning of each setting.
parent ec0bed64
Pipeline #45951 passed with stages
in 13 minutes and 57 seconds
......@@ -82,15 +82,25 @@ sub startup {
if (defined($c->config('ldap'))) {
my $ldap = Net::LDAP->new($c->config->{ldap}->{uri});
my $mesg = $ldap->bind($c->config->{ldap}->{bind_user}.$c->config->{ldap}->{bind_dn},
# connect to the ldap server using the search credentials
my $mesg = $ldap->bind($c->config->{ldap}->{bind_dn},
password => $c->config->{ldap}->{bind_pwd}
$mesg->code && die $mesg->error;
if ($mesg->code) {
$c->app->log->info("[LDAP search authentication failed] login: ".$c->config->{ldap}->{bind_dn});
$c->app->log->error("[LDAP search authentication failed] ".$mesg->error);
return undef;
my $ldap_user_attr = $c->config->{ldap}->{user_attr};
my $ldap_user_filter = $c->config->{ldap}->{user_filter};
# search the ldap database for the user who is trying to login
$mesg = $ldap->search(
base => $c->config->{ldap}->{user_tree},
filter => "(&(uid=$username)".$c->config->{ldap}->{user_filter}.")"
filter => "(&($ldap_user_attr=$username)$ldap_user_filter)"
if ($mesg->code) {
......@@ -98,8 +108,18 @@ sub startup {
return undef;
# check to make sure that the ldap search returned at least one entry
if (scalar $mesg->entries <= 0) {
$c->app->log->error("[LDAP search] no results returned for search");
return undef;
# retrieve the first user returned by the search
my $ldap_userdn = $mesg->entry(0)->{asn}->{objectName};
$c->app->log->debug("[LDAP search] found user dn: ".$ldap_userdn);
# Now we know that the user exists
$mesg = $ldap->bind('uid='.$username.$c->config->{ldap}->{bind_dn},
$mesg = $ldap->bind($ldap_userdn,
password => $password
......@@ -134,12 +134,12 @@
# please note that everybody can still use shortend URLs
# optional, no default
#ldap => {
# uri => 'ldaps://',
# user_tree => 'ou=users,dc=example,dc=org',
# bind_dn => ',ou=users,dc=example,dc=org',
# bind_user => 'uid=ldap_user',
# bind_pwd => 'secr3t',
# user_filter => '!(uid=ldap_user)'
# uri => 'ldaps://', # server URI
# user_tree => 'ou=users,dc=example,dc=org', # search base DN
# bind_dn => 'uid=ldap_user,ou=users,dc=example,dc=org', # search bind DN
# bind_pwd => 'secr3t', # search bind password
# user_attr => 'uid', # user attribute (uid, mail, sAMAccountName, etc.)
# user_filter => '(!(uid=ldap_user))', # user filter (to exclude some users, etc.)
# set `htpasswd` if you want to use an htpasswd file instead of ldap
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment