File Coverage

blib/lib/Apache/Sling/GroupMember.pm
Criterion Covered Total %
statement 103 216 47.6
branch 23 64 35.9
condition 0 6 0.0
subroutine 24 27 88.8
pod 7 13 53.8
total 157 326 48.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             package Apache::Sling::GroupMember;
4              
5 1     1   3361 use 5.008001;
  1         5  
  1         51  
6 1     1   6 use strict;
  1         3  
  1         43  
7 1     1   7 use warnings;
  1         3  
  1         228  
8 1     1   7 use Carp;
  1         1  
  1         120  
9 1     1   2032 use Getopt::Long qw(:config bundling);
  1         31292  
  1         8  
10 1     1   2258 use JSON;
  1         30920  
  1         8  
11 1     1   2248 use Text::CSV;
  1         26227  
  1         6  
12 1     1   41 use Apache::Sling;
  1         3  
  1         56  
13 1     1   627 use Apache::Sling::GroupUtil;
  1         3  
  1         45  
14 1     1   612 use Apache::Sling::GroupMemberUtil;
  1         3  
  1         45  
15 1     1   6 use Apache::Sling::Print;
  1         36  
  1         30  
16 1     1   5 use Apache::Sling::Request;
  1         1  
  1         36  
17              
18             require Exporter;
19              
20 1     1   4 use base qw(Exporter);
  1         2  
  1         4024  
21              
22             our @EXPORT_OK = qw(command_line);
23              
24             our $VERSION = '0.27';
25              
26             #{{{sub new
27              
28             sub new {
29 2     2 1 1360 my ( $class, $authn, $verbose, $log ) = @_;
30 2 100       6 if ( !defined $authn ) { croak 'no authn provided!'; }
  1         34  
31 1         3 my $response;
32 1 50       6 $verbose = ( defined $verbose ? $verbose : 0 );
33 1         13 my $group = {
34 1         2 BaseURL => ${$authn}->{'BaseURL'},
35             Authn => $authn,
36             Message => q{},
37             Response => \$response,
38             Verbose => $verbose,
39             Log => $log
40             };
41 1         4 bless $group, $class;
42 1         4 return $group;
43             }
44              
45             #}}}
46              
47             #{{{sub set_results
48             sub set_results {
49 0     0 1 0 my ( $group, $message, $response ) = @_;
50 0         0 $group->{'Message'} = $message;
51 0         0 $group->{'Response'} = $response;
52 0         0 return 1;
53             }
54              
55             #}}}
56              
57             #{{{sub add
58             sub add {
59 1     1 1 8699 my ( $group, $act_on_group, $add_member ) = @_;
60 1         9 my $res = Apache::Sling::Request::request(
61             \$group,
62             Apache::Sling::GroupMemberUtil::add_setup(
63             $group->{'BaseURL'}, $act_on_group, $add_member
64             )
65             );
66 0         0 my $success = Apache::Sling::GroupMemberUtil::add_eval($res);
67 0         0 my $message = "\"$add_member\" ";
68 0 0       0 $message .= ( $success ? 'added' : 'was not added' );
69 0         0 $message .= " to group \"$act_on_group\"!";
70 0         0 $group->set_results( "$message", $res );
71 0         0 return $success;
72             }
73              
74             #}}}
75              
76             #{{{sub add_from_file
77             sub add_from_file {
78 3     3 1 6514 my ( $group, $file, $fork_id, $number_of_forks ) = @_;
79 3 50       15 $fork_id = defined $fork_id ? $fork_id : 0;
80 3 50       9 $number_of_forks = defined $number_of_forks ? $number_of_forks : 1;
81 3         26 my $csv = Text::CSV->new();
82 3         261 my $count = 0;
83 3         5 my $number_of_columns = 0;
84 3         6 my @column_headings;
85 3 100       10 if ( !defined $file ) {
86 1         16 croak 'File to upload from not defined';
87             }
88 1 100   1   14 if ( open my ($input), '<', $file ) {
  1         2  
  1         12  
  2         99  
89 1         1876 while (<$input>) {
90 1 50       7 if ( $count++ == 0 ) {
    0          
91              
92             # Parse file column headings first to determine field names:
93 1 50       9 if ( $csv->parse($_) ) {
94 1         399 @column_headings = $csv->fields();
95              
96             # First field must be group:
97 1 50       14 if ( $column_headings[0] !~ /^[Gg][Rr][Oo][Uu][Pp]$/msx ) {
98 1         27 croak 'First CSV column must be the group ID, '
99             . 'column heading must be "group". '
100             . 'Found: "'
101             . $column_headings[0] . "\".\n";
102             }
103              
104             # Second field must be user:
105 0 0       0 if ( $column_headings[1] !~ /^[Uu][Ss][Ee][Rr]$/msx ) {
106 0         0 croak 'Second CSV column must be the user ID, '
107             . 'column heading must be "user". '
108             . 'Found: "'
109             . $column_headings[1] . "\".\n";
110             }
111 0         0 $number_of_columns = @column_headings;
112             }
113             else {
114 0         0 croak 'CSV broken, failed to parse line: '
115             . $csv->error_input;
116             }
117             }
118             elsif ( $fork_id == ( $count++ % $number_of_forks ) ) {
119 0 0       0 if ( $csv->parse($_) ) {
120 0         0 my @columns = $csv->fields();
121 0         0 my $columns_size = @columns;
122              
123             # Check row has same number of columns as there were column headings:
124 0 0       0 if ( $columns_size != $number_of_columns ) {
125 0         0 croak
126             "Found \"$columns_size\" columns. There should have been \"$number_of_columns\".\n"
127             . "Row contents was: $_";
128             }
129 0         0 my $act_on_group = $columns[0];
130 0         0 my $add_member = $columns[1];
131 0         0 $group->add( $act_on_group, $add_member );
132 0         0 Apache::Sling::Print::print_result($group);
133             }
134             else {
135 0         0 croak 'CSV broken, failed to parse line: '
136             . $csv->error_input;
137             }
138             }
139             }
140 0 0       0 close $input or croak q{Problem closing input!};
141             }
142             else {
143 1         18 croak "Problem opening file: '$file'";
144             }
145 0         0 return 1;
146             }
147              
148             #}}}
149              
150             #{{{ sub command_line
151             sub command_line {
152 0     0 0 0 my ( $group_member, @ARGV ) = @_;
153 0         0 my $sling = Apache::Sling->new;
154 0         0 my $config = $group_member->config( $sling, @ARGV );
155 0         0 return $group_member->run( $sling, $config );
156             }
157              
158             #}}}
159              
160             #{{{sub config
161              
162             sub config {
163 1     1 1 997 my ( $group_member, $sling, @ARGV ) = @_;
164 1         7 my $group_member_config = $group_member->config_hash( $sling, @ARGV );
165              
166 1 50       9 GetOptions(
167             $group_member_config, 'auth=s',
168             'help|?', 'log|L=s',
169             'man|M', 'pass|p=s',
170             'threads|t=s', 'url|U=s',
171             'user|u=s', 'verbose|v+',
172             'add|a=s', 'additions|A=s',
173             'delete|d=s', 'exists|e=s',
174             'group|g=s', 'view|V'
175             ) or $group_member->help();
176              
177 1         1241 return $group_member_config;
178             }
179              
180             #}}}
181              
182             #{{{sub config_hash
183              
184             sub config_hash {
185 1     1 0 3 my ( $group_member, $sling, @ARGV ) = @_;
186 1         2 my $additions;
187             my $add;
188 0         0 my $delete;
189 0         0 my $exists;
190 0         0 my $group;
191 0         0 my $view;
192              
193 1         24 my %group_member_config = (
194             'auth' => \$sling->{'Auth'},
195             'help' => \$sling->{'Help'},
196             'log' => \$sling->{'Log'},
197             'man' => \$sling->{'Man'},
198             'pass' => \$sling->{'Pass'},
199             'threads' => \$sling->{'Threads'},
200             'url' => \$sling->{'URL'},
201             'user' => \$sling->{'User'},
202             'verbose' => \$sling->{'Verbose'},
203             'add' => \$add,
204             'additions' => \$additions,
205             'delete' => \$delete,
206             'exists' => \$exists,
207             'group' => \$group,
208             'view' => \$view
209             );
210              
211 1         5 return \%group_member_config;
212             }
213              
214             #}}}
215              
216             #{{{sub check_exists
217             sub check_exists {
218 1     1 0 1028 my ( $group, $act_on_group, $exists_member ) = @_;
219 1         10 my $res = Apache::Sling::Request::request(
220             \$group,
221             Apache::Sling::GroupUtil::view_setup(
222             $group->{'BaseURL'}, $act_on_group
223             )
224             );
225 0         0 my $success = Apache::Sling::GroupUtil::view_eval($res);
226 0         0 my $message;
227 0 0       0 if ($success) {
228 0         0 my $group_info = from_json( ${$res}->content );
  0         0  
229 0         0 my $is_member = 0;
230 0         0 foreach my $member ( @{ $group_info->{'members'} } ) {
  0         0  
231 0 0 0     0 if ( $member eq "/system/userManager/user/$exists_member"
      0        
232             || $member eq "/system/userManager/group/$exists_member"
233             || $member eq "$exists_member" )
234             {
235 0         0 $is_member = 1;
236 0         0 last;
237             }
238             }
239 0         0 $success = $is_member;
240 0 0       0 $message =
241             "\"$exists_member\" is "
242             . ( $is_member ? q{} : 'not ' )
243             . "in group \"$act_on_group\"";
244             }
245             else {
246 0         0 $message = "Problem viewing group: \"$act_on_group\"";
247             }
248 0         0 $group->set_results( "$message", $res );
249 0         0 return $success;
250             }
251              
252             #}}}
253              
254             #{{{sub del
255             sub del {
256 1     1 0 1080 my ( $group, $act_on_group, $delete_member ) = @_;
257 1         6 my $res = Apache::Sling::Request::request(
258             \$group,
259             Apache::Sling::GroupMemberUtil::delete_setup(
260             $group->{'BaseURL'}, $act_on_group, $delete_member
261             )
262             );
263 0         0 my $success = Apache::Sling::GroupMemberUtil::delete_eval($res);
264 0         0 my $message = "\"$delete_member\" ";
265 0 0       0 $message .= ( $success ? 'deleted' : 'was not deleted' );
266 0         0 $message .= " from group \"$act_on_group\"!";
267 0         0 $group->set_results( "$message", $res );
268 0         0 return $success;
269             }
270              
271             #}}}
272              
273             #{{{ sub help
274             sub help {
275              
276 1     1 0 1624 print <<"EOF";
277             Usage: perl $0 [-OPTIONS [-MORE_OPTIONS]] [--] [PROGRAM_ARG1 ...]
278             The following options are accepted:
279              
280             --additions or -A (file) - file containing list of members to be added to groups.
281             --add or -a (member) - add specified member.
282             --auth (type) - Specify auth type. If ommitted, default is used.
283             --delete or -d (member) - delete specified group member.
284             --exists or -e (member) - check whether specified member exists in group.
285             --group or -g (actOnGroup) - group to perform membership actions on.
286             --help or -? - view the script synopsis and options.
287             --log or -L (log) - Log script output to specified log file.
288             --man or -M - view the full script documentation.
289             --pass or -p (password) - Password of user performing actions.
290             --threads or -t (threads) - Used with -A, defines number of parallel
291             processes to have running through file.
292             --url or -U (URL) - URL for system being tested against.
293             --user or -u (username) - Name of user to perform any actions as.
294             --verbose or -v or -vv or -vvv - Increase verbosity of output.
295             --view or -V - view members of specified group.
296              
297             Options may be merged together. -- stops processing of options.
298             Space is not required between options and their arguments.
299             For full details run: perl $0 --man
300             EOF
301              
302 1         4 return 1;
303             }
304              
305             #}}}
306              
307             #{{{ sub man
308             sub man {
309              
310 0     0 0 0 my ($group_member) = @_;
311              
312 0         0 print <<'EOF';
313             group membership perl script. Provides a means of managing membership of groups
314             in sling from the command line.
315              
316             EOF
317              
318 0         0 $group_member->help();
319              
320 0         0 print <<"EOF";
321             Example Usage
322              
323             * Authenticate and add a member testuser to the group with id g-test:
324              
325             perl $0 -U http://localhost:8080 -g g-test -u admin -p admin -a testuser
326              
327             * Authenticate and view members of group with id g-test:
328              
329             perl $0 -U http://localhost:8080 -g g-test -u admin -p admin -V
330              
331             * Authenticate and check whether testuser is a member of group with id g-test:
332              
333             perl $0 -U http://localhost:8080 -g g-test -u admin -p admin -e testuser
334              
335             * Authenticate and remove testuser from being a member of group with id g-test with very verbose output:
336              
337             perl $0 -U http://localhost:8080 -g g-test -u admin -p admin -d testuser -vv
338              
339             EOF
340              
341 0         0 return 1;
342             }
343              
344             #}}}
345              
346             #{{{sub run
347             sub run {
348 2     2 1 41 my ( $group_member, $sling, $config ) = @_;
349 2 100       10 if ( !defined $config ) {
350 1         20 croak 'No group_member config supplied!';
351             }
352 1         7 $sling->check_forks;
353 1         4 my $authn =
354             defined $sling->{'Authn'}
355 1 50       7 ? ${ $sling->{'Authn'} }
356             : new Apache::Sling::Authn( \$sling );
357              
358 1         4 my $success = 1;
359              
360 1 50       10 if ( $sling->{'Help'} ) { $group_member->help(); }
  0 50       0  
    50          
361 0         0 elsif ( $sling->{'Man'} ) { $group_member->man(); }
  1         5  
362             elsif ( defined ${ $config->{'additions'} } ) {
363 0         0 my $message =
364 0         0 "Adding groups from file \"" . ${ $config->{'additions'} } . "\":\n";
365 0         0 Apache::Sling::Print::print_with_lock( "$message", $sling->{'Log'} );
366 0         0 my @childs = ();
367 0         0 for my $i ( 0 .. $sling->{'Threads'} ) {
368 0         0 my $pid = fork;
369 0 0       0 if ($pid) { push @childs, $pid; } # parent
  0 0       0  
370             elsif ( $pid == 0 ) { # child
371             # Create a new separate user agent per fork in order to
372             # ensure cookie stores are separate, then log the user in:
373 0         0 $authn->{'LWP'} = $authn->user_agent( $sling->{'Referer'} );
374 0         0 $authn->login_user();
375 0         0 my $group_member =
376             new Apache::Sling::GroupMember( \$authn, $sling->{'Verbose'},
377             $sling->{'Log'} );
378 0         0 $group_member->add_from_file( ${ $config->{'additions'} },
  0         0  
379             $i, $sling->{'Threads'} );
380 0         0 exit 0;
381             }
382             else {
383 0         0 croak "Could not fork $i!";
384             }
385             }
386 0         0 foreach (@childs) { waitpid $_, 0; }
  0         0  
387             }
388             else {
389 1         8 $authn->login_user();
390 1 50       3 if ( defined ${ $config->{'exists'} } ) {
  1 50       5  
  1 50       6  
    50          
391 0         0 $group_member =
392             new Apache::Sling::GroupMember( \$authn, $sling->{'Verbose'},
393             $sling->{'Log'} );
394 0         0 $success = $group_member->check_exists( ${ $config->{'group'} },
  0         0  
395 0         0 ${ $config->{'exists'} } );
396             }
397 1         5 elsif ( defined ${ $config->{'add'} } ) {
398 0         0 $group_member =
399             new Apache::Sling::GroupMember( \$authn, $sling->{'Verbose'},
400             $sling->{'Log'} );
401 0         0 $success = $group_member->add( ${ $config->{'group'} },
  0         0  
402 0         0 ${ $config->{'add'} } );
403             }
404 1         5 elsif ( defined ${ $config->{'delete'} } ) {
405 0         0 $group_member =
406             new Apache::Sling::GroupMember( \$authn, $sling->{'Verbose'},
407             $sling->{'Log'} );
408 0         0 $success = $group_member->del( ${ $config->{'group'} },
  0         0  
409 0         0 ${ $config->{'delete'} } );
410             }
411             elsif ( defined ${ $config->{'view'} } ) {
412 0         0 $group_member =
413             new Apache::Sling::GroupMember( \$authn, $sling->{'Verbose'},
414             $sling->{'Log'} );
415 0         0 $success = $group_member->view( ${ $config->{'group'} } );
  0         0  
416             }
417             else {
418 1         14 $group_member->help();
419 1         7 return 1;
420             }
421 0         0 Apache::Sling::Print::print_result($group_member);
422             }
423 0         0 return $success;
424             }
425              
426             #}}}
427              
428             #{{{sub view
429             sub view {
430 1     1 1 1085 my ( $group, $act_on_group ) = @_;
431 1         22 my $res = Apache::Sling::Request::request(
432             \$group,
433             Apache::Sling::GroupUtil::view_setup(
434             $group->{'BaseURL'}, $act_on_group
435             )
436             );
437 0           my $success = Apache::Sling::GroupUtil::view_eval($res);
438 0           my $message;
439 0 0         if ($success) {
440 0           my $group_info = from_json( ${$res}->content );
  0            
441 0           my $number_members = @{ $group_info->{'members'} };
  0            
442 0           my $members = "$number_members result(s) for group \"$act_on_group\":";
443 0           foreach my $member ( @{ $group_info->{'members'} } ) {
  0            
444 0           $members .= "\n$member";
445             }
446 0           $message = "$members";
447 0           $success = $number_members;
448             }
449             else {
450              
451             # HTTP request did not complete successfully!
452 0           $message = "Problem viewing group: \"$act_on_group\"";
453             }
454 0           $group->set_results( "$message", $res );
455 0           return $success;
456             }
457              
458             #}}}
459              
460             1;
461              
462             __END__