July 24, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Searching Active Directory with Perl

  • November 10, 2003
  • By W. Jason Gilmore
  • Send Email »
  • More Articles »

Assuming that all goes okay, a connection to the LDAP server will have been established, and an object referencing that connection returned. But before you can really do anything with that connection, some credentials must be furnished. This is accomplished with the bind() method, introduced next.

bind()
bind([dn[,options]])

The bind() method serves to furnish credentials, or login, to the server. Both arguments are optional; omitting them will result in an attempt to perform an anonymous bind to the directory server. Anonymous binds are rare, however, therefore you'll almost certainly need to provide a DN (distinguished name) and a password. An example follows:

$ad->bind(.CN=ad-web,DC=ad,DC=wjgilmore,DC=com., password=.secret.);

Alternatively, when talking to Active Directory you can designate the DN using a user@domain argument, like so:

$ad->bind(.ad-web@ad.wjgilmore.com., password=>.secret.);

In addition to password, several other options are available. Each is introduced here:

  • control => HASH: . CONTROL HANDLERS ARE This control must be specified as a hash, with the hash containing three items:
    • type => OID. The OID specifying the type of requested control. This is required.
    • critical => FLAG. The request criticality. This is optional.
    • value=> VALUE. If the requested control requires a value, this element should point to that value.
  • callback => CALLBACK. A callback is a function that is called for every packet received from the server. You can point to that function here.
  • noauth | anonymous => 1. This results in an attempt to bind anonymously. Use of this option is unnecessary, as bind() will by default attempt to bind with no password in the case that one isn't supplied.
  • password => PSWD. Authenticate using this password.
  • sasl => SASLOBJ. This tells the command to bind using a Simple Authentication and Security Layer (SASL) mechanism. The value must be a subclass of Authen::SASL., another module written by perl-ldap's creator.

Once a successful bind is established, you can begin carrying out the necessary tasks.

unbind()
unbind()

Once you're done communicating with the directory server, you should close the connection. This is accomplished with the unbind() method. It accepts no arguments; simply call it at the conclusion of your script:

#!/usr/bin/perl

use strict;
use Net::LDAP;

my $ad = Net::LDAP->new("ad.wjgilmore.com") or die "$0";

$ad->bind("ad-web\@ad.wjgilmore.com", password=>"secret");

# Interact with the directory server here

# Unbind from the server
$ad->unbind;

Thus far, we know how to connect to, login (bind), and logout (unbind) of the directory server. While these actions are all necessary pieces of the puzzle, but we've yet to learn how to actually do anything particularly cool; Not to worry, as the remainder of this tutorial is devoted to a thorough investigation regarding how to use perl-ldap's powerful search capabilities to navigate the directory server.

search()
search(options)

The search() method is used to search a directory, returning an object of class Net::LDAP::Search. It takes as input one or several options, each of which is defined here:

Note. The Net::LDAP::Search class inherits Net::LDAP::Message, meaning that all methods defined in that class are also available to a search object. This class offers a number of useful methods, including those pertinent to retrieving errors which may arise during communication with the directory server. Although I won't formally introduce Net::LDAP::Message, consider reviewing the perl-ldap documentation regarding this matter.

  • base => DN. This determines the distinguished name used as the search target.
  • scope => 'base' | 'one' | 'sub'. This option will override the default behavior of searching the entire directory tree residing within the search target. Setting this option to 'base' will result in the search of just the base object. Setting it to 'one' will result in a search of just the level residing directly below the base object. Setting it to 'sub' will return the behavior to the default.
  • deref => 'always' | 'find' | 'never' | 'search'.
  • sizelimit => N. This option determines the maximum number of returned entities.
  • timelimit => N. This option sets the maximum number of seconds devoted to the search. By default, this is set to infinite.
  • typesonly => 1. Enabling this option results in only the return of the attributes, sans values.
  • filter => FILTER. Including a search filter will impose certain constraints as to which entries are returned. LDAP filters are very similar to the WHERE clause in an SQL query.
  • attrs => [ATTR1, ATTR2, . ATTRN]. You can restrict which attribute->value mappings for an entry are returned. Not including this option will result in the return of all attributes deemed viewable by the bound user.

Let's consider several examples of growing complexity. The first example simply searches for staff member's last names, and returns the total found:

Displaying Number of Entries Retrieved

#!/usr/bin/perl

use strict;
use Net::LDAP;

my $ad = Net::LDAP->new("ad.wjgilmore.com")
                or die "Could not connect!";

$ad->bind("ad-web\@ad.wjgilmore.com", password=>"secret");

# Declare the necessary search variables

# What is the search base?

my $searchbase = 'OU=People,OU=staff,DC=ad,DC=wjgilmore,DC=com';

# What are we searching for?

my $filter = "memberof=CN=staff,OU=groups,DC=ad,DC=wjgilmore,DC=com";

# Which attributes should be returned?

my $attrs = "sn";

# Execute the search

my $results = $ad->search(base=>$searchbase,filter=>$filter,attrs=>$attrs);

# How many entries returned?

my $count = $results->count;

print "Total entries returned: $count\n";

# Unbind from the server

$ad->unbind;

Executing this script results in output similar to:

Total entries returned: 5

Displaying Retrieved Entries

In the next example, we'll modify the previous script to display the retrieved entries. For sake of space, I'll forego repetition of the connection and bind calls; just keep in mind that these commands are requirements of any script.

# The search base?

my $base = 'OU=People,OU=staff,DC=ad,DC=wjgilmore,DC=com';

# What are we searching for?

my $filter = "memberof=CN=staff,OU=groups,DC=ad,DC=wjgilmore,DC=com";

# Which attributes should be returned?

my $attrs = "sn, givenname";

# Execute the search

my $results = $ad->search(base=>$base,filter=>$filter,attrs=>$attrs);

# How many entries returned?

my $count = $results->count;

# Display entries

my $entry;

for (my $i=0; $i<$count; $i++) {

     $entry = $results->entry($i);

     print $entry->get_value('sn').", ".
           $entry->get_value('givenname')."\n";

}

Returning:

Gilmore, Jason
Javascript, Jackie
Perl, Peter
Python, Paul
Mysql, Mary

Looking for a Specific User

In the final introductory example, let's retrieve information specific to a particular user. Note the use of the Time::Local module to convert the number of seconds since the user has last changed his password.

use Time::Local;
# . . .

my $base = 'OU=People,OU=staff,DC=ad,DC=wjgilmore,DC=com';

# What are we searching for?

my $filter = "CN=Jason Gilmore";

# Which attributes should be returned?

my $attrs = "sn, givenname, telephonenumber, mail, pwdLastSet";

# Execute the search

my $results = $ad->search(base=>$base,filter=>$filter,attrs=>$attrs);

# Display entries

my $entry;

$entry = $results->entry(0);

print $entry->get_value('sn').", ".$entry->get_value('givenname')."\n";
print "Tel: ".$entry->get_value('telephonenumber')."\n";
print "Email: ".$entry->get_value('mail')."\n";
print "Password last changed: ".
       localtime($entry->get_value('pwdLastSet'))."\n";

Returning:

Gilmore, Jason
Tel: 614-999-9999
Email: jason@wjgilmore.com
Password last changed: Sat Nov 1 12:45:10 2003




Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel