Subject: | Support for LDAP servers, other than Active Directory |
Added support for servers other than Active Directory.
First checks for user's DN on LDAP server, performing an anonymous bind,
then use that to authenticated bind.
Patch attached.
Subject: | catalyst-plugin-authentication-ldap.diff |
--- /usr/lib/perl5/site_perl/5.8.8/Catalyst/Plugin/Authentication/LDAP.pm 2005-04-27 18:15:12.000000000 -0300
+++ /home/igor/lib/Catalyst/Plugin/Authentication/LDAP.pm 2006-08-07 15:29:31.000000000 -0300
@@ -1,6 +1,7 @@
package Catalyst::Plugin::Authentication::LDAP;
use strict;
+use List::Util qw(first);
use NEXT;
use Net::LDAP;
@@ -20,6 +21,7 @@
user_append => '@mycompany.com',
user_filter => '(&(objectclass=user)(objectcategory=user)(samaccountname=__USER__*))',
group_attribute => 'memberOf',
+ active_directory => 1,
);
$c->login( $user, $password );
$c->logout;
@@ -73,6 +75,12 @@
Optional. Specify which attribute contains the list of groups/roles the user is a member of.
+ active_directory => 1
+
+Optional. You can omit it if you're connecting to servers other than Microsoft Active Directory.
+If omitted, it will not use any of 'user_append' and 'user_context' attributes, searching for
+user's DN before authenticated connection.
+
=head2 METHODS
=over 4
@@ -92,26 +100,52 @@
return 1 if $c->request->{user};
my $ldap_server = $c->config->{authentication}->{ldap_server};
+ my $active_directory = $c->config->{authentication}->{active_directory};
my $dnc = $c->config->{authentication}->{default_naming_context};
my $user_append = $c->config->{authentication}->{user_append} || '';
my $user_context = $c->config->{authentication}->{user_context} || 'cn=users';
my $user_filter = $c->config->{authentication}->{user_filter} ||
'(&(objectclass=user)(objectcategory=user)(samaccountname=__USER__*))';
my $group_attribute = $c->config->{authentication}->{group_attribute} || 'memberOf';
+ my $user_dn = undef;
eval {
my $ldap = Net::LDAP->new( $ldap_server ) or die "Unable to connect to LDAP server $ldap_server: $@";
+ $user_filter =~ s/__USER__/$user/;
+ # usually the username on LDAP servers are the entire user dn. it seems
+ # to not be true on Active Directory servers, so we check if the server
+ # we want to ask is an Active Directory. if not, we must perform an
+ # anonymous bind to search the user's DN for authenticated bind.
+ if ($active_directory) {
+ $user_dn = $user . $user_append;
+ }
+ else {
+ # perform an anonymous bind on ldap server.
+ my $rc = $ldap->bind();
+ die "Server does not allow anonymous bind: " . $rc->error if $rc->code;
+
+ # ldap search to get all possibles DN.
+ my $search = $ldap->search(
+ base => $dnc,
+ scope => "sub",
+ filter => $user_filter,
+ );
+ die "Unable to retrieve DNs for filter: " . $search->error if $search->code;
+
+ ($user_dn) = map { $_->dn } first { $_->dn =~ /$user/ } $search->entries;
+ }
- my $rc = $ldap->bind( $user . $user_append, password => $password );
+ # now we can perform an authenticated bind.
+ my $rc = $ldap->bind( $user_dn, password => $password );
die "User authentication failed for $user: " . $rc->error if $rc->code;
# since most LDAP servers require a password on every connection, we have to query
# the user's groups/roles here and store them in the session, since we won't have the
# password available later
- $user_filter =~ s/__USER__/$user/;
my $search = $ldap->search(
- base => $user_context . "," . $dnc,
- scope => "sub",
+ # again, we must check if we are talking to an Active Directory server.
+ base => (defined $active_directory) ? $user_context . "," . $dnc : $dnc,
+ scope => "sub",
filter => $user_filter,
);
die "Unable to retrieve user details for $user: " . $search->error if $search->code;