Home > Articles

This chapter is from the book

Programming Basics

Since LDAP is a lightweight protocol, programming using LDAP APIs is easy when you have an understanding of the basic concepts. LDAP introduces a lot of new terminology, such as distinguished names, search filters, search scope, and RootDSE, to name a few. Most of these terms do not exist outside the LDAP or X.500 world. Also, the object-oriented information model used for LDAP is substantially different than that of, say, a database. Those who are familiar with object-oriented programming should quickly adjust to LDAP's notion of classes, attributes, and objects.

Information and Naming Models

Before delving into the programmatic aspects of LDAP, you must first have a solid understanding of the LDAP information and naming models used within Active Directory. The Active Directory information model is based on the X.500 model of entries, known as objects, and attributes. An object is defined by a class, which is itself defined by a collection of attributes. A class may inherit attributes from other classes. The Active Directory schema contains the structure for all the classes and attributes that define objects. For more information see Chapter 10, "Schema."

At the root of the class tree is the top class. All classes must inherit directly from the top class or a class that inherited from the top class either directly or indirectly. Figure 3.6 illustrates both cases of directly and indirectly inheriting from the top class. The group class inherits directly from top, whereas the user class inherits from top indirectly via the organizationalPerson class which inherits from the person class which inherits from top.

Figure 3.6 Class hierarchy for the user and group classes.

All objects within Active Directory have a unique name called the distinguished name (DN). This DN is the path you would follow to find the object when traversing the directory tree. For example, the administrator's user object in the xyz.com forest has a DN of "cn=administrator,cn=users,dc=xyz,dc=com." Each component, such as "cn=administrator," of the DN has exactly one parent, in this case "cn=users." This makes the DN of an object unique throughout the forest. For more information on DNs, see RFC 2253.

Connecting, Binding, and Unbinding

Establishing a connection, binding, and unbinding against an LDAP server is straightforward. In LDAP terms, when you bind as a user, you are authenticating as that user. In Listing 3.1, the Perl code shows an example of setting up a connection, binding as the administrator account, and unbinding.

Listing 3.1 Connecting, Binding, and Unbinding as Administrator Using Net::LDAP

use Net::LDAP;
$ldap = Net::LDAP->new('dc1.xyz.com')
  or die "Could not connect: $@";
$result = $ldap->bind('cn=administrator,cn=users,dc=xyz,dc=com',
           password => 'password');
die $result->error if $result->code;
# do stuff
$ldap->unbind; # tear down the connection

One feature Microsoft added as part of its LDAP implementation was the ability to bind with a User Principal Name (UPN). So instead of binding with a DN such as "cn=administrator,cn=users,dc=xyz,dc=com," you can bind with "administrator@xyz.com." The bind statement from Listing 3.1 could be changed as follows:

$result = $ldap->bind('administrator@xyz.com', password => 'password');

Although this is not supported in other directory servers, it is highly recommended when writing applications specifically for Active Directory. The major benefit is that you do not have to hardcode the DN, which contains the path to the user account, in your programs. If someday you want to move the administrator account to a different container or organizational unit, you would have to change all scripts that authenticated using the DN of the administrator. If you are using the UPN, the move is transparent.

RootDSE

The Root Directory Server Entry (RootDSE) is a vital resource in discovering information about an LDAP directory. The RootDSE was added as part of the LDAP v3 specification, so all LDAP v3-compliant directories should have a RootDSE entry. In Active Directory, it should be used as a starting point for your applications to discover what naming contexts are available, where the domain, schema, and configuration naming contexts are located, and which controls are supported. See Figure 3.7 for an example of the information available from the RootDSE of a domain controller. To obtain the RootDSE, perform a search with base equal to "", filter equal to "(objectclass=*)", and the scope set to "base". Since the RootDSE does not require authentication, no binding is necessary. Listing 3.2 uses Net::LDAP to query the RootDSE:

Listing 3.2 Search Method for Accessing RootDSE with Net::LDAP

$ldap = Net::LDAP->new('dc1.xyz.com')
  or die " Could not connect: $@";
# notice the bind isn't called because it is an anonymous connection
$rootdse = $ldap->search(
          base  => '',
          filter => '(objectclass=*)',
          scope => 'base',
);
die $rootdse->error if $rootdse->code;
foreach $entry($rootdse->entries) {
  foreach $attr(sort $entry->attributes) {
   print "$attr: $_\n" foreach $entry->get_value($attr);
  }
}

Figure 3.7 Information returned from RootDSE.

Listing 3.3 shows a shortcut method in Net::LDAP called root_dse() which makes accessing the RootDSE even easier.

Listing 3.3 Shortcut Method for Accessing RootDSE with Net::LDAP

$ldap = Net::LDAP->new('dc1.xyz.com')
  or die "Could not connect: $@";
$rootdse = $ldap->root_dse;
foreach $attr($rootdse->attributes) {
  foreach $value ($rootdse->get_value($attr)) {
   print "$attr: $value\n";
 }
}

Search Filters

Search filters are a very important yet initially very confusing aspect of LDAP. Search filters define the search criteria for querying and obtaining information from a directory. It is very important to have a good understanding of filters because they are commonly used in most LDAP-related APIs, including ADSI.

Filters are to an LDAP server what SQL is to a database server. Unoptimized search filters can negatively impact the performance of an LDAP server just as unoptimized SQL queries can negatively impact a database server.

A filter is a string comprising one or more prefix notation attribute-value comparisons. RFC 2254 defines LDAP search filters in detail. Some example search filters include:

 (objectClass=*)
  All objects
(&(objectCategory=person)(objectClass=user)(sn=Allen))
 All user objects that have an sn (surname/last name) of "Allen"

(!(&(objectCategory=person)(objectClass=user)))
 All non-user objects

(&(objectCategory=computer)(objectClass=computer)(|(cn=a*)(cn=b*)))
 All computer objects that start with either "a" or "b"

Searching

After you have an understanding of search filters, performing LDAP searches is easy. Besides the search filter, three other values are generally in searches. They include the search base, search scope, and returned attributes. Search base is the starting point in the directory tree for the search. If you know specifically where the set of objects you want to query are located, the base should reflect the parent DN of those objects—for example, cn=users,dc=xyz,dc=com for user objects. The search scope determines how far down the directory tree to search. There are three values that can be set for scope: base, which only searches the same level as the DN defined by the base DN setting; onelevel, which will search one level below the base and does not include the base, and subtree which searches the base entry and everything below the base. As you may guess, subtree searches are the most inefficient because they may cover large portions of the directory. Figure 3.8 illustrates the relationship between the various values for scope.

Figure 3.8 Illustration of base, onelevel, and subtree scopes.

Listing 3.4 shows an example search using Net::LDAP that prints all the user objects in AD:

Listing 3.4 Search for All User Objects

$search = $ldap->search(base=>'xyz.com',
            scope=>'subtree',
            filter=>'(&(objectclass=user)(objectcategory=Person))');
die $search->error if $search->code;
print "Total entries returned: ",$search->count,"\n";
print $entry->get_value('cn'),"\n" foreach $entry $search->entries;

There are some general guidelines to follow when performing LDAP searches. Not following these guidelines can result in delayed response times and increased load on your domain controllers:

  • Search filters should include at least one indexed attribute. Similar to a database, when you do not search on indexed attributes in a directory, the query processor must do full scans of the directory tree to find matches. See Appendix B for a list of the default attributes that are indexed in Active Directory.

  • Use a combination of objectCategory and objectClass, not just objectClass, when searching a specific type of object. In many LDAP filter examples, you will see only objectClass used to define the object type to return. This is inefficient because objectClass is a multivalued, nonindexed attribute. On the other hand, objectCategory is single valued and indexed, so a combination of the two should be used when possible.

  • Avoid trailing match searches. Any search that tries to match only the end of a string (for example, cn=*allen) will incur a several second delay. (We've seen as much as 30 seconds!) Microsoft is aware of this problem and reportedly will have a fix in Windows .NET.

  • Properly scope searches so that you only search as deep in the directory tree as necessary. As previously mentioned, subtree searches are the most inefficient because they have to search everything contained under the specified search base. If you perform a subtree search on the root of a forest, for example dc=xyz,dc=com, it will search the entire directory.

  • Use paging (discussed later in the "Advanced Features" section of this chapter) when performing a subtree search that could potentially return a lot of objects. When paging is enabled, the server will be able to stream a large result set in chunks, reducing the server-side memory resources utilized.

Ambiguous Name Resolution

Ambiguous Name Resolution (ANR) is a Microsoft-specific extension to LDAP that allows clients to make simple and efficient searches to Active Directory with commonly used attributes without using complex search filters. You can use the anr attribute for searches and it will handle a lot of the logic needed to process a query over multiple attributes.

The default set of attributes that are searched when using anr include the following:

  • displayName

  • givenName

  • LegacyExchangeDN

  • physicalDeliveryOfficeName

  • proxyAddresses

  • name

  • sAMAccountName

  • sn

For a search filter such as (anr=rallen), the server would return objects that matched any of the previously listed attributes equal to 'rallen*'. If the search term includes a space, the server will attempt to do first/last name processing. For example, if the search filter was (anr=Rob Al), the filter expansion would look like the one in Listing 3.5.

Listing 3.5 ANR Search Filter Expansion

 (|(givenName=Rob Al*)
  (sn=Rob Al*)
  (displayName=Rob Al*)
  (legacyExchangeDN=Rob Al*)
  (name=Rob Al*)
  (physicalDeliveryOfficeName=Rob Al*)
  (proxyAddresses=Rob Al*)
  (saMAccountName=Rob Al*)
  (&(givenName=Rob*)(sn=Al*))
  (&(givenName=Al*)(sn=Rob*))
 )

In the following example, LDIFDE is used to make an ANR query.

C:\>ldifde -f robal.ldif -r "(&(objectclass=user)(objectcategory=User)(anr=rob a
l))"
Connecting to "dc1.xyz.com"
Logging in as current user using SSPI
Exporting directory to file robal.ldif
Searching for entries...
Writing out entries.
1 entries exported

The command has completed successfully.

C:\>type robal.ldif
dn: CN=rallen,CN=Users,DC=xyz,DC=com
changetype: add
accountExpires: 9223372036854775807
badPasswordTime: 126405198031875000
badPwdCount: 20
codePage: 0
cn: rallen
countryCode: 0
displayName: Robbie C. Allen
givenName: Robbie
initials: C
instanceType: 4
lastLogoff: 0
lastLogon: 0
logonCount: 0
distinguishedName: CN=rallen,CN=Users,DC=xyz,DC=com
objectCategory:
N=Person,CN=Schema,CN=Configuration,DC=xyz,DC=com
objectClass: user
objectGUID:: na8r9cjKC0KzTpl+5r4NQw==
objectSid:: AQUAAAAAAAUVAAAAh0irbVS9SKG+x7O/XQQAAA==
primaryGroupID: 513
pwdLastSet: 126405152801406250
name: rallen
sAMAccountName: rallen
sAMAccountType: 805306368
sn: Allen
userAccountControl: 512
userPrincipalName: rallen@xyz.com
uSNChanged: 73062
uSNCreated: 73058
whenChanged: 20010725061440.0Z
whenCreated: 20010725061435.0Z

The attributes used by ANR are configurable. You can specify other attributes to be included in ANR searches by using the Active Directory Schema Snap-in to check the Ambiguous Name Resolution (ANR) box for the attribute. You can also directly set the searchFlags attribute to 5 in the attributeSchema for the attribute you want to include.

NOTE

To include an attribute to be used for ANR, the attribute must also be indexed.

See Appendix B for a program that can display all ANR assigned attributes in Active Directory.

Add, Modify, and Delete

Manipulating objects inside of Active Directory with LDAP is straightforward. Before you can manipulate an object, the DN for the object must be known. The DN is the key that distinguishes it in the directory tree. Listing 3.6 is an example of adding, modifying, and deleting a user object with Net::LDAP.

Listing 3.6 Manipulating an Object with Net::LDAP

# Add jdoe user
$result = $ldap->add (
  dn  => 'cn=jdoe,cn=users,dc=xyz,dc=com',
  attr => [
   cn   => 'jdoe'',
   samaccountname  => 'jdoe',
   userprincipalname => 'jdoe@xyz.com',
   mail       => 'jdoe@xyz.com',
   telephoneNumber  => '911',
   objectclass    => ['user'],
  ],
);
die $result->error if $result->code;
# Modify attributes of jdoe
$result = $ldap->modify('cn=jdoe,cn=users,dc=xyz,dc=com',
  changes => [
   add   => [ sn => 'Doe' ], # populate sn attribute
   delete => [ telephoneNumber => '911'], # remove '911' 
      telephoneNumber   replace => [ mail => 'John.Doe@xyz.com'], 
      # change email address
  ]
);
die $result->error if $result->code;
# Delete jdoe
$result = $ldap->delete("cn=jdoe,cn=users,dc=xyz,dc=com");
die $result->error if $result->code;

LDIF

LDAP Data Interchange Format (LDIF) is an important and versatile component of any LDAP infrastructure. LDIF allows for the contents of a directory to be exported and imported in human-readable format. The LDIF syntax is defined in RFC 2849. As its name implies, LDIF provides a good mechanism for interchanging and applying data to directories. LDIF can serve several purposes. It can act as a backup utility for a directory's data. You can export the contents of the directory to LDIF, and import it back in case of corruption or data loss. LDIF can be used for bulk loading of data into a directory. It can also act as a crude directory synchronization tool among disparate directories.

The Net::LDAP::LDIF module provides a simple interface for reading and writing LDIF files.

$ldif = Net::LDAP::LDIF->new( 'file.ldif', "r" );
@entries = $ldif->read();

Look at the Net::LDAP::LDIF perldoc for more information.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020