Peter Karman wrote on 12/10/09 5:48 PM:
Prashanth Sundaram wrote on 12/10/09 4:59 PM:
   Folks,

I am a n00b to perl scripting and need help to start building my own. I am currently working on a project where the LDAP(389-ds) and Active Directory are always in sync. I have a very minimal set of attributes and conditions
to keep them in sync.

Can anyone share their code, so that I can build around it? Here¹s my
requirement:
* Sync New users from AD to LDAP with attributes: sAMAccountName, sn,
givenName, description, userAccountControl(disable/enable),
* Delete LDAP accounts which are not present in AD and vice versa.
* Generate the next available uidnumber by parsing thru ldap, so new users can be created * Check memberOf for 2 groups and if true add them to corresponding groups
in LDAP

If you have any of these modules written already, that would be great help.
I am digging through the archive looking for related code.

Net::LDAP::Class should make most if not all of those requirements pretty easy to implement. It was written to ease keeping a rdbms, LDAP and AD all in sync.



I suppose I should back that up with some actual code.

I would set it up like this. These files:

 lib/MyLDAP/User.pm
 lib/MyLDAP/Group.pm
 lib/MyAD/User.pm
 lib/MyAD/Group.pm

Containing code like this. (NOTE the code is *NOT* tested).

lib/MyLDAP/User.pm:

 package MyLDAP::User;
 use base qw( Net::LDAP::Class::User::POSIX );

 __PACKAGE__->metadata->setup(
     base_dn             => 'dc=yourcompany,dc=com',
     attributes          => __PACKAGE__->POSIX_attributes,
     unique_attributes   => __PACKAGE__->POSIX_unique_attributes,
 );

 sub init_group_class { 'MyLDAP::Group' }

 1;

lib/MyLDAP/Group.pm:

 package MyLDAP::User;
 use base qw( Net::LDAP::Class::Group::POSIX );

 __PACKAGE__->metadata->setup(
     base_dn             => 'dc=yourcompany,dc=com',
     attributes          => __PACKAGE__->POSIX_attributes,
     unique_attributes   => __PACKAGE__->POSIX_unique_attributes,
 );

 sub init_user_class { 'MyLDAP::User' }

 1;

lib/MyAD/User.pm:

 package MyAD::User;
 use base qw( Net::LDAP::Class::User::AD );

 __PACKAGE__->metadata->setup(
     base_dn             => 'dc=yourcompany,dc=com',
     attributes          => __PACKAGE__->AD_attributes,
     unique_attributes   => __PACKAGE__->AD_unique_attributes,
 );

 sub init_group_class { 'MyAD::Group' }

 1;

lib/MyAD/Group.pm:

 package MyAD::Group;
 use base qw( Net::LDAP::Class::Group::AD );

 __PACKAGE__->metadata->setup(
     base_dn             => 'dc=yourcompany,dc=com',
     attributes          => __PACKAGE__->AD_attributes,
     unique_attributes   => __PACKAGE__->AD_unique_attributes,
 );

 sub init_user_class { 'MyAD::User' }

 1;



Now you have your .pm class files set up, and you can write a script (or more likely, multiple scripts, one per action) to use them to handle all your requirements:

 # example to sync between AD and LDAP based on uid/sAMAccountName (username)
 use strict;
 use warnings;
 use lib 'lib';
 use Net::LDAP;
 use MyLDAP::User;
 use MyLDAP::Group;
 use MyAD::User;
 use MyAD::Group;

 # create all the ldap connections and bind
 my $ldap_dn   = 'your-authenticated-user-dn';
 my $ldap_pass = 'your-authenticated-user-password';
 my $ldap_host = 'ldap://yourldapserver';
 my $ldap      = Net::LDAP->new($ldap_host);

 my $ad_dn     = 'your-authenticated-user-dn';
 my $ad_pass   = 'your-authenticated-user-password';
 my $ad_host   = 'ldap://youradserver';
 my $ad        = Net::LDAP->new($ad_host);

 # could use ssl cert here too instead of password
 my $mesg = $ldap->bind( $ldap_dn, password => $ldap_pass );
 $mesg->code and die Net::LDAP::Class->get_ldap_error($mesg);
 $mesg    = $ad->bind( $ad_dn, password => $ad_pass );
 $mesg->code and die Net::LDAP::Class->get_ldap_error($mesg);

 # iterate over all LDAP users, checking if they are in AD
 my $num_ldap_checked = MyLDAP::User->act_on_all(
     \&check_ldap_users,
     { ldap => $ldap }
 );

 sub check_ldap_users {
     my $ldap_user = shift;
     my $ad_user = MyAD::User->new( ldap => $ad, username => "$ldap_user" );
     if (!$ad_user->read) {
         warn "$ldap_user is not in AD!";

         # decide what action should be taken. Delete from ldap?
         $ldap_user->delete;

         # or create a AD user?
         # add them with whatever attributes you need
         # see the perldoc for Net::LDAP::Class::User::AD
         # ...
         # then save to AD
         $ad_user->create or die "can't create AD user $ad_user";
     }
 }

 # now do the reverse, checking AD
 my $num_ad_checked = MyAD::User->new(
     \&check_ad_users,
     { ldap => $ad }
 );

 sub check_ad_users {
     my $ad_user = shift;

     # similar to above in check_ldap_users.
 }

 print "Checked $num_ldap_checked LDAP users and $num_ad_checked AD users\n";
 exit(0);



The basic idea is that you can set up .pm classes to handle all the dirty work of managing user/group relationships, setting attributes, reading/writing from the server, etc, and then use those classes over and over in your management scripts.

--
Peter Karman  .  http://peknet.com/  .  pe...@peknet.com

Reply via email to