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