An Introduction to perl-ldap
If you have a large number of users on your system, it's likely you do not want to add each new user to the system one by one, through a GUI. So, one of the first things you write is a script that quickly adds lots of users in bulk. Or, perhaps you'll write a Web-based system where users can enter their personal information for themselves, with LDAP entries being added automatically. The add() method is used for adding an entry to the database:
$result = $ldap->add("uid=john,ou=People,dc=leapster,dc=org",
attr => [ 'cn' => 'John Smith',
'sn' => 'Smith',
'uid' => 'john',
'givenName' => 'John',
'homePhone' => '555-2020',
'mail' => 'john@domain.name',
'objectclass' => [ 'person', 'inetOrgPerson']
]
);
The above snippet of code adds a user named John Smith to our database. As you can see, the attributes are provided as a list to the attr parameter. Any attribute to which you wish to give multiple values should have them supplied as a list (in our example above, objectclass is such an attribute).
We're now at the point where we can write a simple script to add our large number of users in bulk, a script I've called ldap_addusers.
#!/usr/bin/perl
use Net::LDAP;
$ldap = Net::LDAP->new("localhost");
$ldap->bind("cn=admin,dc=leapster,dc=org", password=>"secret");
while(<>) {
chomp $_;
($uid,$givenName,$sn,$mail) = split(/:/,$_);
$cn="$givenName $sn";
$dn="uid=$uid,ou=People,dc=leapster,dc=org";
$result = $ldap->add($dn,
attr => [ 'uid' => $uid,
'cn' => $cn,
'sn' => $sn,
'mail' => $mail,
'givenName' => $givenName,
'objectclass' => [ 'person', 'inetOrgPerson']
]
);
$result->code && warn "error: ", $result->error;
}
The above script takes a colon-separated file of users, one per line, on stdin:
tom:Tom:Jones:tom@domain.name dick:Dick:Tracy:dick@domain.name harry:Harry:Windsor:harry@domain.name
So, if these names are stored in a file called userlist, we can enter them into our LDAP database with the ldap_addusers script, as follows:
cat userlist | ./ldap_addusers
There's one line in the ldap_addusers script that we haven't seen before:
$result->code && warn "error: ", $result->error;
As mentioned earlier, the add() method returns an object of type Net::LDAP::Message. Here, this object is referenced by $result. $result->code is the code value returned from the LDAP server in the result message after a query (in this case, the request to add an entry). Generally, when the request is successful, a zero is returned. Hence, in our above statement, the warning is issued only when $result->code is not zero.
Some other useful methods in Net::LDAP::Message are:
$result->dn The DN contained in the result message $result->error The error message in the result (only if there was an error) $result->done True if the request was completed $result->is_error True if the particular result is an error for the operation
For a full description of the other methods, see the perldoc manual for Net::LDAP::Message.
perl-ldap also provides the delete() method for deleting entries, when given their DN:
$dn="uid=paul,ou=People,dc=leapster,dc=org"; $ldap->delete($dn);
This would, for example, allow you to write a script to do a bulk delete of expired users from your system:
#!/usr/bin/perl
use Net::LDAP;
$ldap = Net::LDAP->new("localhost");
$ldap->bind("cn=admin,dc=leapster,dc=org", password=>"secret");
while(<>) {
chomp $_;
$dn="uid=$_,ou=People,dc=leapster,dc=org";
$ldap->delete($dn);
}
This script deletes all users whose uids are fed to it on standard input, one per line. Be careful when using this script on production servers; if you accidentally feed it the wrong file, you may find yourself with no users left in your directory.
It wouldn't be much use only to be able to write to our LDAP server; we need to be able to read from it also. The perl-ldap search command is used to perform lookups on an LDAP server.
$mesg = $ldap->search(filter=>"(uid=paul)", base=>"dc=leapster,dc=org");
The base parameter specifies the base object entry from which the search will be made. In the example above, it searches the entire LDAP tree. The search could be confined to only the ou=People branch with:
$mesg = $ldap->search( filter=>"(uid=paul)",
base=>"ou=People,dc=leapster,dc=org");
A number of other optional parameters are available to the search() method:
scope : This can be one of the following:
base: Search the base object only
one: Search only the entries one level below the base
sub: Search the entire subtree below the base
If I knew no subtrees were below ou=People--or if there were, but I didn't want results returned from them--I could use:
$mesg = $ldap->search( filter=>"(uid=paul)", base=>"ou=People,dc=leapster,dc=org" scope=>"one");timelimit: Set a limit in seconds on the amount of time that a request may take. The default is 0, which signals that the time is unlimited.
attrs: Set the attributes (as a reference to an array) that should be returned in the search. If not provided, the search returns all of the attributes. For example, the following search returns only the uid, sn and givenName attributes:
$mesg = $ldap->search( filter=>"(uid=paul)", base=>"ou=People,dc=leapster,dc=org", attrs=> ['uid', 'sn', 'givenName'] );filter: The filter may be a string, in standard LDAP filter format (see the ldap_search(3) man page for a description of this), or it may be a Net::LDAP::Filter object (see the Net::LDAP:Filter man page for further information).
The search() method returns Net::LDAP::Search objects. The easiest way to get at the contents of this object is to use its entries() method, which returns an array of Net::LDAP::Entry objects (see below):
@entries = $mesg->entries;
The Net::LDAP::Search object also has a number of other useful methods:
$mesg->count; The number of entries returned in the search $mesg->entry(n); Returns the n'th entry (initial entry is 0) $mesg->sorted([list]) Returns a list of entry objects sorted by attr list
Now, we can write a small script to list every entry in the directory:
#!/usr/bin/perl
use Net::LDAP;
$ldap = Net::LDAP->new("localhost");
$ldap->bind("cn=admin,dc=leapster,dc=org", password=>"secret");
$mesg = $ldap->search(filter=>"(objectClass=*)", base=>"dc=leapster,dc=org");
@entries = $mesg->entries;
foreach $entry (@entries) {
$entry->dump;
}
I've cheated a little in the above script and used the dump() method of Net::LDAP::Entry, in order to make things clearer. dump() primarily is used for debugging; it merely dumps the DN and contents of an entry straight to standard output, without allowing for any manipulation of the results.
The most commonly used methods of the Net::LDAP::Entry object are:
attributes: returns the list of attributes contained in this entry.
@attrs = $entry->attributes();
dn: Returns the DN of the current entry. If given with a parameter, it sets the DN of the entry:
$dn = "uid=pbd,ou=Users,dc=leapster,dc=org"; $entry->dn($dn);
get_value: obtains the value or values for the attribute, given as a parameter. If this method is used to assign to a scalar variable, it returns only the first value for the attribute; if used with an array, it returns all of the attributes.
$phone = $entry->get_value("homePhone"); # returns only one phone number @phone = $entry->get_value("homePhone"); # returns all phone numbers for entryadd, delete, modify: These methods allow changes to be made to the entry and are discussed further in the next section.
update: pushes any changes made to the entry to the LDAP server (whose object is given as a parameter):
$entry->add(homePhone => "555 3034"); $entry->update($ldap);
Now that we've examined the Net::LDAP::Entry object, we can expand the above script further. We can write out the contents of the entries ourselves:
#!/usr/bin/perl
use Net::LDAP;
$ldap = Net::LDAP->new("localhost");
$ldap->bind("cn=admin,dc=leapster,dc=org", password=>"secret");
$mesg = $ldap->search(filter=>"(objectClass=*)", base=>"dc=leapster,dc=org");
@entries = $mesg->entries;
foreach $entry (@entries) {
print "dn: " . $entry->dn() . "\n";
@attrs = $entry->attributes();
foreach $attr (@attrs) {
printf("\t%s: %s\n", $attr, $entry->get_value($attr));
}
}
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
- RSS Feeds
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- Dynamic DNS—an Object Lesson in Problem Solving
- New Products
- Validate an E-Mail Address with PHP, the Right Way
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Download the Free Red Hat White Paper "Using an Open Source Framework to Catch the Bad Guy"
- Tech Tip: Really Simple HTTP Server with Python
- Keeping track of IP address
1 hour 12 min ago - Roll your own dynamic dns
6 hours 25 min ago - Please correct the URL for Salt Stack's web site
9 hours 36 min ago - Android is Linux -- why no better inter-operation
11 hours 52 min ago - Connecting Android device to desktop Linux via USB
12 hours 20 min ago - Find new cell phone and tablet pc
13 hours 18 min ago - Epistle
14 hours 47 min ago - Automatically updating Guest Additions
15 hours 56 min ago - I like your topic on android
16 hours 42 min ago - This is the easiest tutorial
23 hours 18 min ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?



Comments
Awesome Work
Awesome codes and illustrations.
Would have appreciated more if the Acronyms were clear.
How to add UserAccountControl
How to add user ACcount Control Parameter ,it not working ?
UID
Cannot figure what the value of UID should be? I can dump all the contents with filter set as (objectclass=*) and get around 200 entries ; But, when I try to search for a particular UId, I do not get any results back. can anyone tell me what value should be put in for UID to search? I tried with filter=>"(uid=vinda)" filter=>"(uid=vinda norman)" filter=>"(uid=norman)" but no luck.
dn: CN=vinda Norman,OU=Users,OU=SysStaff,OU=SBCS,DC=ad,DC=cs,DC=sunysb,DC=edu
objectClass: top
cn: Vinda Norman
sn: Norman
givenName: Vinda
distinguishedName: CN=Vinda Norman,OU=Users,OU=SysStaff,OU=SBCS,DC=ad,DC=cs,DC=sunysb,DC=edu
instanceType: 4
whenCreated: 20080904132500.0Z
whenChanged: 20090906023318.0Z
displayName: Vinda norman
uSNCreated: 9019
memberOf: CN=System Staff Users,CN=Users,DC=ad,DC=cs,DC=sunysb,DC=edu
uSNChanged: 778762
name: Vinda Norman
objectGUID: *nÄsM¹lN_Aö
userAccountControl: 512
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 128975058670944212
lastLogoff: 0
lastLogon: 128975753602883244
pwdLastSet: 128965394154875698
primaryGroupID: 513
objectSid: ªl²p!Xù{®MZ
accountExpires: 9223372036854775807
logonCount: 267
sAMAccountName: vinda
sAMAccountType: 805306368
userPrincipalName: vinda@ad.cs.sunysb.edu
What happens if bind fails
$mesg = $ldap->bind("cn=admin,dc=leapster,dc=org", password=>"secret");
I tried this, but even with a wrong password, this line did not give an error.
you mean it still connects
you mean it still connects to LDAP?
This tutorial has helped me
This tutorial has helped me created a whole project in one week. This was exactly what i needed! Good job
use warnings; use strict;
use warnings;
use strict;
perl-ldap vs. PerLDAP
Not be be confused with another project, PerLDAP, which started back when Netscape was king. I had used PerLDAP for years, before perl-ldap even existed. It's now part of the Mozilla Foundation and is available here: http://www.mozilla.org/directory/perldap.html
The one downside is that it requires the Netscape Directory SDK. But it's free and available for almost any platform.
PerLDAP came after perl-ldap
PerLDAP was originally Net::LDAPapi by Clayton Donley. Netscape announced taking over the module and renaming it PerLDAP at the second perl conference, which was held in San Jose in August 1998.
perl-ldap (Net::LDAP) and Net::LDAPapi projects were both started in 1997 about the same time.
PerLDAP can be difficult to get working though!
I've been trying to get Bugzilla to work with PerLDAP, and while I can successfully compile the Netscape directory code, I can't get PerLDAP itself to compile - too many miconfigurations it appears, maybe some problems with versioning b/w PerLDAP & Netscape's SDK. Anyway, I gave up, and I now use Paul's patch to bugzilla which allows bugzilla to work with Net::LDAP. Cheers Paul.