File Coverage

blib/lib/Apache/Sling/LDAPSynch.pm
Criterion Covered Total %
statement 104 365 28.4
branch 25 134 18.6
condition 2 9 22.2
subroutine 21 37 56.7
pod 19 23 82.6
total 171 568 30.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             package Apache::Sling::LDAPSynch;
4              
5 1     1   2636 use 5.008001;
  1         3  
  1         38  
6 1     1   4 use strict;
  1         2  
  1         29  
7 1     1   73 use warnings;
  1         2  
  1         26  
8 1     1   12 use Carp;
  1         2  
  1         59  
9 1     1   1188 use Getopt::Long qw(:config bundling);
  1         404919  
  1         10  
10 1     1   285 use Apache::Sling;
  1         2  
  1         43  
11 1     1   6 use Apache::Sling::Authn;
  1         3  
  1         42  
12 1     1   912 use Apache::Sling::Content;
  1         3  
  1         70  
13 1     1   1085 use Apache::Sling::User;
  1         3  
  1         47  
14 1     1   1114 use Data::Dumper;
  1         5866  
  1         69  
15 1     1   9 use Fcntl ':flock';
  1         2  
  1         141  
16 1     1   5 use File::Temp;
  1         2  
  1         72  
17 1     1   927 use Net::LDAP;
  1         187380  
  1         9  
18              
19             require Exporter;
20              
21 1     1   94 use base qw(Exporter);
  1         2  
  1         4864  
22              
23             our @EXPORT_OK = qw(command_line);
24              
25             our $VERSION = '0.27';
26              
27             #{{{sub new
28              
29             sub new {
30             my (
31 2     2 1 1530 $class, $ldap_host, $ldap_base, $filter, $dn,
32             $pass, $authn, $disabled, $verbose, $log
33             ) = @_;
34 2 100       8 if ( !defined $authn ) { croak 'no authn provided!'; }
  1         38  
35 1 50       5 $disabled = ( defined $disabled ? $disabled : q(sling:disabled) );
36 1 50       5 $filter = ( defined $filter ? $filter : q(uid) );
37 1 50       4 $verbose = ( defined $verbose ? $verbose : 0 );
38              
39             # Directory containing the cache and user_list files:
40 1         2 my $synch_cache_path =
41             q(_user/a/ad/admin/private/ldap_synch_cache_system_files);
42              
43             # Directory containing backups of the cache and user_list files:
44 1         3 my $synch_cache_backup_path =
45             q(_user/a/ad/admin/private/ldap_synch_cache_system_files_backup);
46              
47             # List of specific users previously ingested in to the sling system and their status:
48 1         1 my $synch_cache_file = q(cache.txt);
49              
50             # List of specific ldap users that are to be ingested in to the sling system:
51 1         4 my $synch_user_list = q(user_list.txt);
52 1         1 my $ldap;
53 1 50       10 my $content = Apache::Sling::Content->new( $authn, $verbose, $log )
54             or croak q(Problem creating Sling content object!);
55 1 50       12 my $user = Apache::Sling::User->new( $authn, $verbose, $log )
56             or croak q(Problem creating Sling user object!);
57 1         16 my $ldap_synch = {
58             CacheBackupPath => $synch_cache_backup_path,
59             CachePath => $synch_cache_path,
60             CacheFile => $synch_cache_file,
61             Content => \$content,
62             Disabled => $disabled,
63             LDAP => \$ldap,
64             LDAPbase => $ldap_base,
65             LDAPDN => $dn,
66             LDAPHost => $ldap_host,
67             LDAPPass => $pass,
68             Filter => $filter,
69             Log => $log,
70             Message => q(),
71             User => \$user,
72             UserList => $synch_user_list,
73             Verbose => $verbose
74             };
75 1         2 bless $ldap_synch, $class;
76 1         3 return $ldap_synch;
77             }
78              
79             #}}}
80              
81             #{{{sub ldap_connect
82              
83             sub ldap_connect {
84 0     0 1 0 my ($class) = @_;
85 0 0       0 $class->{'LDAP'} = Net::LDAP->new( $class->{'LDAPHost'} )
86             or croak 'Problem opening a connection to the LDAP server!';
87 0 0 0     0 if ( defined $class->{'LDAPDN'} && defined $class->{'LDAPPASS'} ) {
88 0 0       0 my $mesg = $class->{'LDAP'}->bind(
89             $class->{'LDAPDN'},
90             password => $class->{'LDAPPASS'},
91             version => '3'
92             ) or croak 'Problem with authenticated bind to LDAP server!';
93             }
94             else {
95 0 0       0 my $mesg = $class->{'LDAP'}->bind( version => '3' )
96             or croak 'Problem with anonymous bind to LDAP server!';
97             }
98 0         0 return 1;
99             }
100              
101             #}}}
102              
103             #{{{sub ldap_search
104              
105             sub ldap_search {
106 0     0 1 0 my ( $class, $search, $attrs ) = @_;
107 0         0 $class->ldap_connect;
108 0         0 return $class->{'LDAP'}->search(
109             base => $class->{'LDAPbase'},
110             scope => 'sub',
111             filter => "$search",
112             attrs => $attrs
113             )->as_struct;
114             }
115              
116             #}}}
117              
118             #{{{sub init_synch_cache
119              
120             sub init_synch_cache {
121 0     0 1 0 my ($class) = @_;
122 0 0       0 if ( !${ $class->{'Content'} }
  0         0  
123             ->check_exists( $class->{'CachePath'} . q(/) . $class->{'CacheFile'} ) )
124             {
125 0         0 my ( $tmp_cache_file_handle, $tmp_cache_file_name ) =
126             File::Temp::tempfile();
127 0         0 my %synch_cache;
128 0 0       0 print {$tmp_cache_file_handle}
  0         0  
129             Data::Dumper->Dump( [ \%synch_cache ], [qw( synch_cache )] )
130             or croak q(Unable to print initial data dump of synch cache to file!);
131 0 0       0 close $tmp_cache_file_handle
132             or croak
133             q(Problem closing temporary file handle when initializing synch cache);
134 0 0       0 ${ $class->{'Content'} }
  0         0  
135             ->upload_file( $tmp_cache_file_name, $class->{'CachePath'},
136             $class->{'CacheFile'} )
137             or croak q(Unable to initialize LDAP synch cache file!);
138 0 0       0 unlink $tmp_cache_file_name
139             or croak
140             q(Problem clearing up temporary file after init of synch cache!);
141             }
142 0         0 return 1;
143             }
144              
145             #}}}
146              
147             #{{{sub get_synch_cache
148              
149             sub get_synch_cache {
150 0     0 1 0 my ($class) = @_;
151 0         0 $class->init_synch_cache();
152 0 0       0 if ( !${ $class->{'Content'} }
  0         0  
153             ->check_exists( $class->{'CachePath'} . q(/) . $class->{'CacheFile'} ) )
154             {
155 0         0 croak q(No synch cache file present - initialization must have failed!);
156             }
157 0 0       0 ${ $class->{'Content'} }
  0         0  
158             ->view_file( $class->{'CachePath'} . q(/) . $class->{'CacheFile'} )
159             or croak q(Problem viewing synch cache file);
160 0         0 my $synch_cache;
161 0         0 my $success = eval ${ $class->{'Content'} }->{'Message'};
  0         0  
162 0 0       0 if ( !defined $success ) {
163 0         0 croak q{Error parsing synchronized cache dump.};
164             }
165 0         0 return $synch_cache;
166             }
167              
168             #}}}
169              
170             #{{{sub update_synch_cache
171              
172             sub update_synch_cache {
173 0     0 1 0 my ( $class, $synch_cache ) = @_;
174 0         0 my ( $tmp_cache_file_handle, $tmp_cache_file_name ) =
175             File::Temp::tempfile();
176 0 0       0 print {$tmp_cache_file_handle}
  0         0  
177             Data::Dumper->Dump( [$synch_cache], [qw( synch_cache )] )
178             or croak q(Unable to print data dump of synch cache to file!);
179 0 0       0 close $tmp_cache_file_handle
180             or croak
181             q(Problem closing temporary file handle when updating synch cache);
182 0 0       0 ${ $class->{'Content'} }
  0         0  
183             ->upload_file( $tmp_cache_file_name, $class->{'CachePath'},
184             $class->{'CacheFile'} )
185             or croak q(Unable to update LDAP synch cache file!);
186 0         0 my $time = time;
187 0 0       0 ${ $class->{'Content'} }
  0         0  
188             ->upload_file( $tmp_cache_file_name, $class->{'CacheBackupPath'},
189             "cache$time.txt" )
190             or croak q(Unable to create LDAP synch cache backup file!);
191 0 0       0 unlink $tmp_cache_file_name
192             or croak
193             q(Problem clearing up temporary file after updating synch cache!);
194 0         0 return 1;
195             }
196              
197             #}}}
198              
199             #{{{sub get_synch_user_list
200              
201             sub get_synch_user_list {
202 0     0 1 0 my ($class) = @_;
203 0 0       0 if ( !${ $class->{'Content'} }
  0         0  
204             ->check_exists( $class->{'CachePath'} . q(/) . $class->{'UserList'} ) )
205             {
206 0         0 croak q(No user list file present - you need to create one!);
207             }
208 0 0       0 ${ $class->{'Content'} }
  0         0  
209             ->view_file( $class->{'CachePath'} . q(/) . $class->{'UserList'} )
210             or croak q(Problem viewing synch user list);
211 0         0 my $synch_user_list;
212 0         0 my $success = eval ${ $class->{'Content'} }->{'Message'};
  0         0  
213 0 0       0 if ( !defined $success ) {
214 0         0 croak q{Error parsing synchronized user list dump.};
215             }
216 0         0 return $synch_user_list;
217             }
218              
219             #}}}
220              
221             #{{{sub update_synch_user_list
222              
223             sub update_synch_user_list {
224 0     0 1 0 my ( $class, $synch_user_list ) = @_;
225 0         0 my ( $tmp_user_list_file_handle, $tmp_user_list_file_name ) =
226             File::Temp::tempfile();
227 0 0       0 print {$tmp_user_list_file_handle}
  0         0  
228             Data::Dumper->Dump( [$synch_user_list], [qw( synch_user_list )] )
229             or croak q(Unable to print data dump of synch user list to file!);
230 0 0       0 close $tmp_user_list_file_handle
231             or croak
232             q(Problem closing temporary file handle when writing synch user list);
233 0 0       0 ${ $class->{'Content'} }
  0         0  
234             ->upload_file( $tmp_user_list_file_name, $class->{'CachePath'},
235             $class->{'UserList'} )
236             or croak
237             q(Unable to upload LDAP synch user list file into sling instance!);
238 0         0 Apache::Sling::Print::print_result( ${ $class->{'Content'} } );
  0         0  
239 0         0 my $time = time;
240 0 0       0 ${ $class->{'Content'} }
  0         0  
241             ->upload_file( $tmp_user_list_file_name, $class->{'CacheBackupPath'},
242             "user_list$time.txt" )
243             or croak q(Unable to create LDAP synch user list backup file!);
244 0 0       0 unlink $tmp_user_list_file_name
245             or croak
246             q(Problem clearing up temporary file after updating synch user list!);
247 0         0 return 1;
248             }
249              
250             #}}}
251              
252             #{{{sub download_synch_user_list
253              
254             sub download_synch_user_list {
255 0     0 1 0 my ( $class, $user_list_file ) = @_;
256 0         0 my $synch_user_list = $class->get_synch_user_list;
257 0         0 foreach my $user ( sort keys %{$synch_user_list} ) {
  0         0  
258 0 0       0 if ( open my $out, '>>', $user_list_file ) {
259 0         0 flock $out, LOCK_EX;
260 0 0       0 print {$out} $user . "\n"
  0         0  
261             or croak
262             q(Problem printing when downloading synchronized user list!);
263 0         0 flock $out, LOCK_UN;
264 0 0       0 close $out
265             or croak
266             q(Problem closing file handle when downloading synchronized user list!);
267             }
268             else {
269 0         0 croak q(Could not open file to download synchronized user list to!);
270             }
271             }
272 0         0 $class->{'Message'} =
273             "Successfully downloaded user list to $user_list_file!";
274 0         0 return 1;
275             }
276              
277             #}}}
278              
279             #{{{sub upload_synch_user_list
280              
281             sub upload_synch_user_list {
282 0     0 1 0 my ( $class, $user_list_file ) = @_;
283 0         0 my %user_list_hash;
284 0 0       0 if ( open my ($input), '<', $user_list_file ) {
285 0         0 while (<$input>) {
286 0         0 chomp;
287 0         0 $user_list_hash{$_} = 1;
288             }
289 0 0       0 close $input or croak q(Problem closing upload user list file handle!);
290             }
291             else {
292 0         0 croak q(Unable to open synch user list file to parse for upload!);
293             }
294 0         0 $class->update_synch_user_list( \%user_list_hash );
295 0         0 $class->{'Message'} =
296             q(Successfully uploaded user list for use in subsequent synchronizations!);
297 0         0 return 1;
298             }
299              
300             #}}}
301              
302             #{{{sub parse_attributes
303              
304             sub parse_attributes {
305 3     3 1 427 my ( $ldap_attrs, $sling_attrs, $ldap_attrs_array, $sling_attrs_array ) =
306             @_;
307 3 100 66     17 if ( defined $ldap_attrs_array && defined $sling_attrs_array ) {
308 2 50       4 if ( defined $ldap_attrs ) {
309 2         6 @{$ldap_attrs_array} = split /,/msx, $ldap_attrs;
  2         6  
310             }
311 2 50       5 if ( defined $sling_attrs ) {
312 2         5 @{$sling_attrs_array} = split /,/msx, $sling_attrs;
  2         4  
313             }
314 2 100       4 if ( @{$ldap_attrs_array} != @{$sling_attrs_array} ) {
  2         3  
  2         6  
315 1         18 croak
316             q(Number of ldap attributes must match number of sling attributes, )
317 1         15 . @{$ldap_attrs_array} . ' != '
318 1         2 . @{$sling_attrs_array};
319             }
320             }
321 2         8 return 1;
322             }
323              
324             #}}}
325              
326             #{{{sub check_for_property_modifications
327              
328             sub check_for_property_modifications {
329 1     1 1 3 my ( $new_properties, $cached_properties ) = @_;
330 1         2 foreach my $property_key ( keys %{$new_properties} ) {
  1         11  
331 1 50       5 if ( !defined $cached_properties->{$property_key} ) {
332              
333             # Found a newly specified property:
334 1         6 return 1;
335             }
336 0 0       0 if ( $new_properties->{$property_key} ne
337             $cached_properties->{$property_key} )
338             {
339              
340             # Found a modified property:
341 0         0 return 1;
342             }
343             }
344 0         0 return 0;
345             }
346              
347             #}}}
348              
349             #{{{sub perform_synchronization
350              
351             sub perform_synchronization {
352 0     0 1 0 my ( $class, $array_of_dns, $search_result, $seen_user_ids, $synch_cache,
353             $ldap_attrs_array, $sling_attrs_array )
354             = @_;
355 0         0 foreach my $dn ( @{$array_of_dns} ) {
  0         0  
356 0         0 my $valref = $search_result->{$dn};
357 0         0 my $index = 0;
358 0         0 my $user_id = @{ $valref->{ $class->{'Filter'} } }[0];
  0         0  
359 0         0 $seen_user_ids->{$user_id} = 1;
360 0         0 my @properties_array;
361             my %properties_hash;
362 0         0 foreach my $ldap_attr ( @{$ldap_attrs_array} ) {
  0         0  
363 0         0 my $value = @{ $valref->{$ldap_attr} }[0];
  0         0  
364 0 0       0 if ( defined $value ) {
365 0         0 push @properties_array,
366 0         0 @{$sling_attrs_array}[$index] . q(=) . $value;
367 0         0 $properties_hash{ @{$sling_attrs_array}[$index] } = $value;
  0         0  
368             }
369 0         0 $index++;
370             }
371 0 0       0 if ( defined $synch_cache->{$user_id} ) {
372              
373             # We already know about this user from a previous run:
374 0 0       0 if ( $synch_cache->{$user_id}->{ $class->{'Disabled'} } eq '1' ) {
375              
376             # User was previously disabled. Re-enabling:
377 0         0 push @properties_array, $class->{'Disabled'} . '=0';
378 0 0       0 print "Re-enabling previously disabled user: $user_id\n"
379             or croak q{Problem printing!};
380 0 0       0 ${ $class->{'User'} }->update( $user_id, \@properties_array )
  0         0  
381             or croak q(Problem re-enabling user in sling instance!);
382 0         0 $synch_cache->{$user_id} = \%properties_hash;
383 0         0 $synch_cache->{$user_id}->{ $class->{'Disabled'} } = '0';
384             }
385             else {
386              
387             # User is enabled in sling already, check for modifications:
388 0 0       0 if (
389 0         0 check_for_property_modifications(
390             \%properties_hash, \%{ $synch_cache->{$user_id} }
391             )
392             )
393             {
394              
395             # Modifications are present, so we need to update:
396 0 0       0 print "Updating existing user $user_id\n"
397             or croak q{Problem printing!};
398 0 0       0 ${ $class->{'User'} }
  0         0  
399             ->update( $user_id, \@properties_array )
400             or croak q(Problem updating user in sling instance!);
401 0         0 $properties_hash{ $class->{'Disabled'} } = '0';
402 0         0 $synch_cache->{$user_id} = \%properties_hash;
403             }
404             else {
405              
406             # No modifications present, nothing to do!
407 0 0       0 print "No user modifications, skipping: $user_id\n"
408             or croak q{Problem printing!};
409             }
410             }
411             }
412             else {
413              
414             # We have never seen this user before:
415 0 0       0 print "Creating new user: $user_id\n" or croak q{Problem printing!};
416 0 0       0 ${ $class->{'User'} }
  0         0  
417             ->add( $user_id, 'password', \@properties_array )
418             or croak q(Problem adding new user to sling instance!);
419 0         0 $properties_hash{ $class->{'Disabled'} } = '0';
420 0         0 $synch_cache->{$user_id} = \%properties_hash;
421             }
422             }
423 0         0 return 0;
424             }
425              
426             #}}}
427              
428             #{{{sub synch_full
429              
430             sub synch_full {
431 0     0 1 0 my ( $class, $ldap_attrs, $sling_attrs ) = @_;
432 0         0 my $search = q{(} . $class->{'Filter'} . q{=*)};
433 0         0 my @ldap_attrs_array;
434             my @sling_attrs_array;
435 0 0       0 parse_attributes( $ldap_attrs, $sling_attrs, \@ldap_attrs_array,
436             \@sling_attrs_array )
437             or croak q(Problem parsing attributes!);
438              
439             # We need to capture the id as well as any attributes:
440 0         0 unshift @ldap_attrs_array, $class->{'Filter'};
441 0         0 my $search_result = $class->ldap_search( $search, \@ldap_attrs_array );
442 0         0 shift @ldap_attrs_array;
443              
444 0         0 my $synch_cache = $class->get_synch_cache;
445 0         0 my %seen_user_ids;
446              
447             # process each DN using it as a key
448 0         0 my @array_of_dns = sort keys %{$search_result};
  0         0  
449              
450 0         0 $class->perform_synchronization(
451             \@array_of_dns, $search_result, \%seen_user_ids,
452             $synch_cache, \@ldap_attrs_array, \@sling_attrs_array
453             );
454              
455             # Clean up records no longer in ldap:
456 0         0 my @disable_property;
457 0         0 push @disable_property, $class->{'Disabled'} . '=1';
458 0         0 foreach my $cache_entry ( sort keys %{$synch_cache} ) {
  0         0  
459 0 0 0     0 if ( $synch_cache->{$cache_entry}->{ $class->{'Disabled'} } eq '0'
460             && !defined $seen_user_ids{$cache_entry} )
461             {
462 0 0       0 print
463             "Disabling user record in sling that no longer exists in ldap: $cache_entry\n"
464             or croak q{Problem printing!};
465 0 0       0 ${ $class->{'User'} }->update( $cache_entry, \@disable_property )
  0         0  
466             or croak q(Problem disabling user in sling instance!);
467 0         0 $synch_cache->{$cache_entry}->{ $class->{'Disabled'} } = '1';
468             }
469             }
470 0         0 $class->update_synch_cache($synch_cache);
471              
472 0         0 $class->{'Message'} = 'Successfully performed a full synchronization!';
473 0         0 return 1;
474             }
475              
476             #}}}
477              
478             #{{{sub synch_full_since
479              
480             sub synch_full_since {
481 0     0 1 0 my ( $class, $ldap_attrs, $sling_attrs, $synch_since ) = @_;
482 0         0 my $search = q{(modifytimestamp>=} . $synch_since . q{)};
483 0         0 my $search_result = $class->ldap_search( $search, $ldap_attrs );
484 0         0 croak q(Function not yet fully supported!);
485              
486             # return 1;
487             }
488              
489             #}}}
490              
491             #{{{sub synch_listed
492              
493             sub synch_listed {
494 0     0 1 0 my ( $class, $ldap_attrs, $sling_attrs ) = @_;
495 0         0 my $search = q{(} . $class->{'Filter'} . q{=*)};
496 0         0 my $search_result = $class->ldap_search( $search, $ldap_attrs );
497 0         0 croak q(Function not yet fully supported!);
498              
499             # return 1;
500             }
501              
502             #}}}
503              
504             #{{{sub synch_listed_since
505              
506             sub synch_listed_since {
507 0     0 1 0 my ( $class, $ldap_attrs, $sling_attrs, $synch_since ) = @_;
508 0         0 my $search = q{(} . $class->{'Filter'} . q{=*)};
509 0         0 my $search_result = $class->ldap_search( $search, $ldap_attrs );
510 0         0 croak q(Function not yet fully supported!);
511              
512             # return 1;
513             }
514              
515             #}}}
516              
517             #{{{ sub command_line
518             sub command_line {
519 0     0 0 0 my ( $ldap_synch, @ARGV ) = @_;
520 0         0 my $sling = Apache::Sling->new;
521 0         0 my $config = $ldap_synch->config( $sling, @ARGV );
522 0         0 return $ldap_synch->run( $sling, $config );
523             }
524              
525             #}}}
526              
527             #{{{sub config
528              
529             sub config {
530 1     1 1 3 my ( $ldap_synch, $sling, @ARGV ) = @_;
531 1         5 my $ldap_synch_config = $ldap_synch->config_hash( $sling, @ARGV );
532              
533 1 50       20 GetOptions(
534             $ldap_synch_config, 'auth=s',
535             'help|?', 'log|L=s',
536             'man|M', 'pass|p=s',
537             'threads|t=s', 'url|U=s',
538             'user|u=s', 'verbose|v+',
539             'download-user-list', 'ldap-attributes|a=s',
540             'ldap-base|b=s', 'ldap-dn|d=s',
541             'ldap-filter|f=s', 'ldap-host|h=s',
542             'ldap-pass|P=s', 'attributes|A=s',
543             'synch-full|s', 'synch-full-since|S=s',
544             'synch-listed|l', 'synch-listed-since',
545             'upload-user-list'
546             ) or $ldap_synch->help();
547              
548 1         1667 return $ldap_synch_config;
549             }
550              
551             #}}}
552              
553             #{{{sub config_hash
554              
555             sub config_hash {
556 1     1 0 3 my ( $ldap_synch, $sling, @ARGV ) = @_;
557 1         2 my $attributes;
558             my $download_user_list;
559 0         0 my $flag_disabled;
560 0         0 my $ldap_attributes;
561 0         0 my $ldap_base;
562 0         0 my $ldap_dn;
563 0         0 my $ldap_filter;
564 0         0 my $ldap_host;
565 0         0 my $ldap_pass;
566 0         0 my $synch_full;
567 0         0 my $synch_full_since;
568 0         0 my $synch_listed;
569 0         0 my $synch_listed_since;
570 0         0 my $upload_user_list;
571              
572 1         26 my %ldap_synch_config = (
573             'auth' => \$sling->{'Auth'},
574             'help' => \$sling->{'Help'},
575             'log' => \$sling->{'Log'},
576             'man' => \$sling->{'Man'},
577             'pass' => \$sling->{'Pass'},
578             'threads' => \$sling->{'Threads'},
579             'url' => \$sling->{'URL'},
580             'user' => \$sling->{'User'},
581             'verbose' => \$sling->{'Verbose'},
582             'attributes' => $attributes,
583             'download-user-list' => $download_user_list,
584             'flag-disabled' => $flag_disabled,
585             'ldap-attributes' => $ldap_attributes,
586             'ldap-base' => $ldap_base,
587             'ldap-dn' => $ldap_dn,
588             'ldap-filter' => $ldap_filter,
589             'ldap-host' => $ldap_host,
590             'ldap-pass' => $ldap_pass,
591             'synch-full' => $synch_full,
592             'synch-full-since' => $synch_full_since,
593             'synch-listed' => $synch_listed,
594             'synch-listed-since' => $synch_listed_since,
595             'upload-user-list' => $upload_user_list
596             );
597              
598 1         4 return \%ldap_synch_config;
599             }
600              
601             #}}}
602              
603             #{{{ sub help
604             sub help {
605              
606 1     1 0 2010 print <<"EOF";
607             Usage: perl $0 [-OPTIONS [-MORE_OPTIONS]] [--] [PROGRAM_ARG1 ...]
608             The following options are accepted:
609              
610             --attributes or -a (attribs) - Comma separated list of attributes.
611             --auth (type) - Specify auth type. If ommitted, default is used.
612             --download-user-list (userList) - Download user list to file userList
613             --flag-disabled or -f - property to denote user should be disabled.
614             --help or -? - View the script synopsis and options.
615             --ldap-attributes or -A (attribs) - Specify ldap attributes to be updated.
616             --ldap-base or -B (ldapBase) - Specify ldap base to synchronize users from.
617             --ldap-dn or -D (ldapDN) - Specify ldap DN for authentication.
618             --ldap-filter or -F (filter) - Specify ldap attribute to search for users with.
619             --ldap-host or -H (host) - Specify ldap host to synchronize from.
620             --ldap-pass or -P (pass) - Specify ldap pass for authentication.
621             --log or -L (log) - Log script output to specified log file.
622             --man or -M - View the full script documentation.
623             --pass or -p (password) - Password of user performing actions.
624             --synch-full or -s - Perform a full synchronization from ldap to sling.
625             --synch-full-since or -S (since) - Perform a full synchronization from ldap to sling using changes since specified time.
626             --synch-listed or -l - Perform a sychronization of listed users from ldap to sling.
627             --synch-listed-since (since) - Perform a sychronization of listed users from ldap to sling using changes since specified time.
628             --upload-user-list (userList) - Upload user list specified by file userList.
629             --url or -U (URL) - URL for system being tested against.
630             --user or -u (username) - Name of user to perform any actions as.
631             --verbose or -v or -vv or -vvv - Increase verbosity of output.
632              
633             Options may be merged together. -- stops processing of options.
634             Space is not required between options and their arguments.
635             For full details run: perl $0 --man
636             EOF
637              
638 1         5 return 1;
639             }
640              
641             #}}}
642              
643             #{{{ sub man
644             sub man {
645              
646 0     0 0 0 my ($ldap_synch) = @_;
647              
648 0         0 print <<'EOF';
649             LDAP synchronization perl script. Provides a means of synchronizing user
650             information from an LDAP server into a running sling instance from the command
651             line. The script also acts as a reference implementation for the LDAPSynch perl
652             library.
653              
654             EOF
655              
656 0         0 $ldap_synch->help();
657              
658 0         0 print <<"EOF";
659             Example Usage
660              
661             * Upload a restricted list of users (one id per line of specified file) to use in synchronizations:
662              
663             perl $0 --upload-user-list user_list.txt --sling-host http://localhost:8080 --sling-user admin --sling-pass admin
664              
665             * Download a previously specified list of users to be synchronized to a specified file:
666              
667             perl $0 --download-user-list user_list.txt --sling-host http://localhost:8080 --sling-user admin --sling-pass admin
668              
669             * Authenticate and perform a full synchronization:
670              
671             perl $0 -s -h ldap://ldap.org -b "ou=people,o=ldap,dc=org" -H http://localhost:8080 -u admin -P admin -a "displayname,mail,sn" -A "name,email,surname"
672             EOF
673              
674 0         0 return 1;
675             }
676              
677             #}}}
678              
679             #{{{sub run
680             sub run {
681 2     2 1 44 my ( $ldap_synch, $sling, $config ) = @_;
682 2 100       6 if ( !defined $config ) {
683 1         25 croak 'No ldap_synch config supplied!';
684             }
685 1         7 $sling->check_forks;
686              
687 1         10 my $authn = new Apache::Sling::Authn( \$sling );
688 1         5 $authn->login_user();
689              
690 1         2 my $success = 1;
691              
692 1 50       8 if ( $sling->{'Help'} ) { $ldap_synch->help(); }
  0 50       0  
    50          
    50          
    50          
    50          
    50          
    50          
693 0         0 elsif ( $sling->{'Man'} ) { $ldap_synch->man(); }
  1         13  
694 1         6 elsif ( defined ${ $config->{'download-user-list'} } ) {
695 0         0 $ldap_synch = new Apache::Sling::LDAPSynch(
696 0         0 ${ $config->{'ldap-host'} },
697 0         0 ${ $config->{'ldap-base'} },
698 0         0 ${ $config->{'ldap-filter'} },
699 0         0 ${ $config->{'ldap-dn'} },
700 0         0 ${ $config->{'ldap-pass'} },
701             \$authn,
702 0         0 ${ $config->{'flag-disabled'} },
703             $sling->{'Verbose'},
704             $sling->{'Log'}
705             );
706 0         0 $success = $ldap_synch->download_synch_user_list(
707 0         0 ${ $config->{'download-user-list'} } );
708             }
709 1         5 elsif ( defined ${ $config->{'upload-user-list'} } ) {
710 0         0 $ldap_synch = new Apache::Sling::LDAPSynch(
711 0         0 ${ $config->{'ldap-host'} },
712 0         0 ${ $config->{'ldap-base'} },
713 0         0 ${ $config->{'ldap-filter'} },
714 0         0 ${ $config->{'ldap-dn'} },
715 0         0 ${ $config->{'ldap-pass'} },
716             \$authn,
717 0         0 ${ $config->{'flag-disabled'} },
718             $sling->{'Verbose'},
719             $sling->{'Log'}
720             );
721 0         0 $success = $ldap_synch->upload_synch_user_list(
722 0         0 ${ $config->{'upload-user-list'} } );
723             }
724 1         5 elsif ( defined ${ $config->{'synch-full'} } ) {
725 0         0 $ldap_synch = new Apache::Sling::LDAPSynch(
726 0         0 ${ $config->{'ldap-host'} },
727 0         0 ${ $config->{'ldap-base'} },
728 0         0 ${ $config->{'ldap-filter'} },
729 0         0 ${ $config->{'ldap-dn'} },
730 0         0 ${ $config->{'ldap-pass'} },
731             \$authn,
732 0         0 ${ $config->{'flag-disabled'} },
733             $sling->{'Verbose'},
734             $sling->{'Log'}
735             );
736 0         0 $success = $ldap_synch->synch_full( ${ $config->{'ldap-attributes'} },
  0         0  
737 0         0 ${ $config->{'attributes'} } );
738             }
739 1         5 elsif ( defined ${ $config->{'synch-full-since'} } ) {
740 0         0 $ldap_synch = new Apache::Sling::LDAPSynch(
741 0         0 ${ $config->{'ldap-host'} },
742 0         0 ${ $config->{'ldap-base'} },
743 0         0 ${ $config->{'ldap-filter'} },
744 0         0 ${ $config->{'ldap-dn'} },
745 0         0 ${ $config->{'ldap-pass'} },
746             \$authn,
747 0         0 ${ $config->{'flag-disabled'} },
748             $sling->{'Verbose'},
749             $sling->{'Log'}
750             );
751 0         0 $success = $ldap_synch->synch_full_since(
752 0         0 ${ $config->{'ldap-attributes'} },
753 0         0 ${ $config->{'attributes'} },
754 0         0 ${ $config->{'synch-full-since'} }
755             );
756             }
757 1         5 elsif ( defined ${ $config->{'synch-listed'} } ) {
758 0         0 $ldap_synch = new Apache::Sling::LDAPSynch(
759 0         0 ${ $config->{'ldap-host'} },
760 0         0 ${ $config->{'ldap-base'} },
761 0         0 ${ $config->{'ldap-filter'} },
762 0         0 ${ $config->{'ldap-dn'} },
763 0         0 ${ $config->{'ldap-pass'} },
764             \$authn,
765 0         0 ${ $config->{'flag-disabled'} },
766             $sling->{'Verbose'},
767             $sling->{'Log'}
768             );
769 0         0 $success = $ldap_synch->synch_listed( ${ $config->{'ldap-attributes'} },
  0         0  
770 0         0 ${ $config->{'attributes'} } );
771             }
772             elsif ( defined ${ $config->{'synch-listed-since'} } ) {
773 0         0 $ldap_synch = new Apache::Sling::LDAPSynch(
774 0         0 ${ $config->{'ldap-host'} },
775 0         0 ${ $config->{'ldap-base'} },
776 0         0 ${ $config->{'ldap-filter'} },
777 0         0 ${ $config->{'ldap-dn'} },
778 0         0 ${ $config->{'ldap-pass'} },
779             \$authn,
780 0         0 ${ $config->{'flag-disabled'} },
781             $sling->{'Verbose'},
782             $sling->{'Log'}
783             );
784 0         0 $success = $ldap_synch->synch_listed_since(
785 0         0 ${ $config->{'ldap-attributes'} },
786 0         0 ${ $config->{'attributes'} },
787 0         0 ${ $config->{'synch-listed-since'} }
788             );
789             }
790             else {
791 1         7 $ldap_synch->help();
792 1         11 return 1;
793             }
794 0           Apache::Sling::Print::print_result($ldap_synch);
795 0           return $success;
796             }
797              
798             #}}}
799              
800             1;
801              
802             __END__