develooper Front page | perl.ldap | Postings from April 2003

Subclass proposal: Net::LDAP::Simple

Thread Next
Marco Marongiu
April 28, 2003 03:54
Subclass proposal: Net::LDAP::Simple
Message ID:
Hello there, my name is Marco Marongiu. I am brand new on this list so 
if I am violating any rule or convention here I apologize. I am writing 
here after exchanging a couple of e-mails with Graham Barr.

A couple of weeks I asked some opinions on the site about 
the idea of subclassing Net::LDAP to get a simplified interface. I am 
sorry I didn't think about posting *here* the same RFC, but here we go...

What do I mean "simplified"? I'll try to show it by means of two examples.

Example 1: you have to retrieve a number of entries in a subtree based 
on the contents of certain attributes, say cn, uid, loginName. The 
attributes remain the same, but you change the search string. You'll use 
a filter like (|(cn~=marco)(|(uid~=marco)(loginName~=marco)); then 
you'll pass the filter to the search method, along with the base (the 
same for all searches) and all the other parameters you need. After 
that, you need to check the returned Search object for errors and, in 
case of success, extract the entries to do the job; then start over with 
another similar filter and so on.

I'd like to have a method to which I pass a "query string" and it does 
all the job for me, returning a reference to an array of entries for 
success or undef on failure -and, of course, I'd like to have a chance 
of seeing what actually made my search go wrong.

Example 2: You have to read a bunch of entries from a directory server, 
modifying some attributes and then update them on another server -to fix 
the ideas you can think of reading entries from an iPlanet DS with NIS 
gateway and putting them into some Windows Active Directory server. The 
algorithm is about the same as above: search, check return message, 
extract entries, modify them, push them one by one on the other server, 
check the return message each time.

I'd like to have a method that allows me to add an array of entries, and 
that returns a reference to an array containing the entries that made it 
in the directory server; in case of problems (input array has different 
length than the output) I'd like to have a chance to see what happened.

In short: I don't want to go and check the return code if I don't have 
to, and I'd be happy if I had "array operations" on entries.

I thought that it could be a good idea to create a subclass that offered 
such a simplified interface, and that Net::LDAP::Simple could be a name 
that fit. Then I read the (excellent) Sam Tregar's book "Writing Perl 
modules for CPAN" and he warned to ask for namespace owner's consensus 
before publishing anything. That's why I am here.

I wouldn't post the module to CPAN if I won't have enough consensus or 
if you'll send me reasonable objections. But, in that case, I beg you to 
suggest a different, appropriate namespace.

Enough talking. Below is the content of the manpage. If it is allowed on 
the list, I'll post the gzipped tarball too, it's less than 9kB. Just 
let me know.

Thanks in advance for any suggestions and sorry for not contacting you 



     Net::LDAP::Simple - Simplified interface for Net::LDAP

       use Net::LDAP::Simple;

       # connect and bind to a directory server
       # bindDN and bindpw are optional, if you don't specify them an
       # anonymous bind is performed
       # base is the base subtree for searches, it is an optional parameter
       # searchattrs are the attributes that are used by the simplesearch()
       # method.
       eval {
         my $ldap =
           Net::LDAP::Simple->new(host => 'localhost',
                                  bindDN => 'cn=admin,ou=People,dc=me',
                                  bindpw => 'secret',
                                  base   => 'ou=People,dc=me',
                                  searchattrs => [qw(cn uid loginname)],
                                  %parms) ; # params for Net::LDAP::new
       } ;

       if ($@) {
         die "Can't connect to ldap server: $@" ;

       my $filter = '(|(loginname=~bronto)(|(cn=~bronto)(uid=~bronto)))' ;
       my $entries ;
       # These all return the same array of Net::LDAP::Entry objects
       $entries = $ldap->search(filter => $filter) ; # uses new()'s base
       $entries = $ldap->search(base   => 'ou=People,dc=me',
                                filter => $filter) ;
       $entries = $ldap->simplesearch('bronto') ; # uses new()'s searchattrs

       # Now elaborate results:
       foreach my $entry (@$entries) {
         modify_something_in_this($entry) ;

       # You often want to update a set of entries
       foreach my $entry (@$entries) {
         die "Error updating entry" unless defined $ldap->update($entry) ;

       # but you can also do this:
       my $result = $ldap->update(@$entries) ;
       unless (@$result == @$entries) {
         print "Error updating entries: ",$ldap->error,
               "; code ",$ldap->errcode,".\n\n" ;

       # Add an entry, or an array of them, works as above:
       die $ldap->error unless $ldap->add($entry) ;

       # rename an entry: sometimes you simply want to change a name
       # and nothing else...
       $ldap->rename($entry,$newrdn) ;

     Net::LDAP::Simple is a simplified interface to the fantastic Graham
     Barr's Net::LDAP. Net::LDAP is a great module for working with
     directory servers, but it's a bit overkill when you want to do
     simple short scripts or have big programs that always do the same
     job again and again, say: open an authenticated connection to a
     directory server, search entries against the same attributes each
     time and in the same way (e.g.: approx search against the three
     attributes cn, uid and loginname). With Net::LDAP this would mean:

     *   connect to the directory server using new();

     *   authenticate with bind() ;

     *   compose a search filter, and pass it to search(), along with the
         base subtree;

     *   perform the search getting a Net::LDAP::Search object;

     *   verify that the search was successful using the code() or
         is_error() method on the search object;

     *   if the search was successful, extract the entries from the
         Search object, for example with entries or shift_entry.

     With Net::LDAP::Simple this is done with:

     *   connect, authenticate, define default search subtree and
         simple-search attributes with the new() method;

     *   pass the simplesearch method a search string to be matched
         against the attributes defined with searchattrs in new() and
         check the return value: if it was successful you have a
         reference to an array of Net::LDAP::Entry objects, if it was
         unsuccessful you get undef, and you can check what the error was
         with the error() method (or the error code with errcode) ;

         Creates a Net::LDAP::Simple object. Accepts all the parameters
         that are legal to Net::LDAP::new but the directory server
         name/address is specified via the "host" parameter. Specific
         Net::LDAP::Simple parameters are therefore:

             the name or IP address of the directory server we are
             connecting to. Mandatory.

             bind DN in case of authenticated bind

             bind password in case of authenticated bind

             base subtree for searches. ***(Mandatory or optional?)

             attributes to use for simple searches (see the simplesearch

             boolean operator in case that more than one attribute is
             specified with searchattrs; default is '|' (boolean or);
             allowed boolean operators are | and &.

             By default, an 'approx' search is performed by
             simplesearch(); for those directory servers that doesn't
             support the ~= operator it is possible to request a
             substring search specifying the value 'substr' for the
             searchmatch parameter.

             A list of attributes that should be returned in addition of
             the default ones.

     All Net::LDAP methods are supported via inheritance. Method specific
     in Net::LDAP::Simple or that override inherited methods are
     documented below.

     add If you pass it a scalar DN as first parameter, it will proxy the
         method call to Net::LDAP::add and it will behave the sane way
         returning a Net::LDAP::Message object. Or you can pass it one or
         more Net::LDAP::Entry objects, and it will return a reference to
         an array of Net::LDAP::Entry objects that successfully made it
         on the directory server. You can check if every entry has been
         added by comparing the length of the input list against the
         length of the output list. Use the error and/or errorcode
         methods to see what went wrong.

         Works the same way as "add", but it deletes entries instead :-)

         search works exactly as Net::LDAP::search() does, however it
         takes advantage of the defaults set with new(): uses new()'s
         base parameter if you don't specify another base, and adds
         searchextras to default attributes unless you specify an "attrs"

         Another change in the search() interface is the return value:
         now search() returns a reference to an array of entries for
         success, or undef on error.

         Passing a plain string to "search" just proxyies the call to the
         method "simplesearch".

         NOTE: Actually, I am undecided if this is a good thing. I am
         pondering if search should simply be inherited by the
         superclass... I'd like to have some feedback about that.

         Renames an entry; $entry can be a Net::LDAP::Entry or a DN,
         $newrdn is a new value for the RDN. Returns $entry for success,
         undef on failure.

         update takes a list of Net::LDAP::Entry objects as arguments and
         commits changes on the directory server. Returns a reference to
         an array of updated entries.

         Searches entries using the new()'s search* and base parameters.
         Takes a search string as argument. Returns a list of entries on
         success, undef on error.

         Returns last error's name

         Returns last error's code

     Marco Marongiu, <>


Marco Marongiu                         Email:
CRS4 Research Center                   Phone: +39 070 2796 336
NCS Division                           Fax:   +39 070 2796 216
NSM Group                              WWW:

Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About