Search code examples
perlldap-querynetldap

Checking User Groups in Perl Net::LDAP


I have a Perl Subversion pre-commit hook that allows me to verify whether or not a user has permissions to change or add to a particular point in a Subversion repository. It uses a Control file that looks like this:

[GROUP SERVER]
users = bob, ted, carol, alice

[GROUP CLIENT]
users = tom, dick, harry

[FILE Client Developers don't touch the Server]
file = proj/server
users = @CLIENT
permission = read-only

[FILE Server people don't touch the Client]
file = proj/client
users = @SERVER
permission = read-only

[FILE Let Tom Do everything]
file = .*
users = tom
permission = read-write

As you can see, I can define groups and use groups when setting permissions. I thought it would be a hoot if I could use the LDAP groups to do the same. That way, our Windows administrators can figure out who's in what group which gives me more time to keep my Facebook status up to date.

I have LDAP configured as thus in Subversion:

<Location /mfx>
    DAV svn
    SVNParentPath /subversion/svn_repos
    AuthType basic
    AuthName "Source Repository"
    AuthBasicProvider ldap
    AuthzLDAPAuthoritative off
    AuthLDAPURL "ldap://ldapserver:3268/dc=mycompany,dc=com?sAMAccountName" NONE
    AuthLDAPBindDN "CN=SubVersion,OU=Users,OU=Accounts,DC=mycompany,DC=com"
    AuthLDAPBindPassword "Swordfish"
    Require valid-user
</Location>

I've got the connection to our LDAP server working fine, but now, I need to find out what groups that user is in. I have the user's Subversion name in $svnUser, and now I need to find that user in our LDAP database, and verify the various groups they're in (which is the memberOf value in their LDAP record). However, I have no idea how to go about this.

So far, my code looks like this:

#! /usr/bin/env perl
#

use strict;
use warnings;
use feature qw(say);

use constant {
    LDAP_URL => "ldapserver",
    LDAP_PORT => 3268,
    LDAP_SCHEME => "ldap",
    BIND_DN => "CN=SubVersion,OU=Users,OU=Accounts,DC=mycompany,DC=com",
    BIND_PWORD => "Swordfish",
    USER_DN => "sAMAccountName",
};

use Net::LDAP;

#
#  Create LDAP Connection
#

my $ldap = Net::LDAP->new(LDAP_URL, port=> LDAP_PORT, scheme=> LDAP_SCHEME);
my $message;

$message = $ldap->bind(BIND_DN, password => BIND_PWORD);

if ($message->code != 0) {
    die qq(Error in LDAP Binding: ) . $message->error_desc;
}

Now, I need to do $ldap->search, but on what? I'm just befuddled by the syntax.


Solution

  • All right, it took me a while, but I figured it out...

    It would have been helpful if there was some sample code, but after reading a few LDAP documents, I found out I could do something like this:

    (sAMAccountName=$user)
    

    So I tried this:

    my $results = $ldap->search(filter => USER_DN . "=$svnUser",
                                attrs  => "memberOf");
    

    I thought this would return only the attributes of memberOf, but didn't. In fact, it returned an array of a single member although I knew this particular user was a member of three groups.

    It took me a while to realize that it was returning a Net::LDAP::Search object which meant I had to look up that module to find the methods. From there, I found that I could use the pop_entry method to retrieve a Net::LDAP::Entry object. Okay, another CPAN page to find.

    From there, I can do a get_value method on the sMAAccountName, and get an array of DNs that represent the group that person belongs to. I can now parse those names for the groups that Subversion will use.

    This means I can now use Windows Groups in my pre-commit script to set write permissions in my repository. This makes it much, much easier to maintain.