File Coverage

File:/home/mik/work/module/Tivoli/AccessManager/Admin/User.pm
Coverage:99.2%

linestmtbrancondsubpodtimecode
1package Tivoli::AccessManager::Admin::User;
2
15
15
15
165
78
235
use strict;
3
15
15
15
238
61
218
use warnings;
4
15
15
15
212
59
409
use Data::Dumper;
5
15
15
15
221
61
293
use Carp;
6
15
15
15
229
62
262
use Tivoli::AccessManager::Admin::Response;
7
15
15
15
210
65
276
use Tivoli::AccessManager::Admin::Group;
8
9#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
10# $Id: User.pm 334 2006-11-20 19:09:35Z mik $
11#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
12$Tivoli::AccessManager::Admin::User::VERSION = '0.04';
13
15
232
use Inline(C => 'DATA',
14                INC => '-I/opt/PolicyDirector/include',
15                LIBS => ' -lpthread -lpdadminapi -lstdc++',
16                CCFLAGS => '-Wall',
17# VERSION => '0.04',
18                NAME => 'Tivoli::AccessManager::Admin::User',
19
15
15
192
82
          );
20
21my %tod = ( 1 => 'sun',
22            2 => 'mon',
23            4 => 'tue',
24            8 => 'wed',
25           16 => 'thu',
26           32 => 'fri',
27           64 => 'sat',
28     );
29
30my %revtod = map { $tod{$_} => $_ } keys %tod;
31
32sub _todtolist {
33
5
35
    my $vector = shift;
34
5
21
    my @list;
35
36
5
63
    return qw/any/ unless $vector;
37
38
4
48
54
385
    for my $mask ( sort { $a <=> $b } keys %tod ) {
39
28
286
        push @list, $tod{$mask} if ( ($vector & $mask) == $mask );
40    }
41
4
93
    return @list;
42}
43
44sub _listtotod {
45
5
25
    my $list = shift;
46
5
23
    my $vector = 0;
47
48
5
5
22
40
    for my $day ( @{$list} ) {
49
11
53
        $day = lc($day);
50
11
79
        if ( $day eq 'any' ) {
51
2
15
            $vector = 0;
52
2
12
            last;
53        }
54
9
58
        $vector += $revtod{$day};
55    }
56
5
42
    return $vector;
57}
58
59sub _miltomin {
60
12
74
    my $miltime = shift;
61
12
127
    return ( $miltime - $miltime % 100 ) * .6 + $miltime % 100;
62}
63
64sub _mintomil {
65
10
49
    my $mins = shift;
66
67
10
175
    return sprintf("%04d", ($mins - $mins % 60)/.6 + $mins % 60);
68}
69
70sub new {
71
38
1
551
    my $class = shift;
72
38
176
    my $cont = shift;
73
38
970
    unless ( defined($cont) and UNIVERSAL::isa($cont,'Tivoli::AccessManager::Admin::Context' ) ) {
74
2
69
        warn "Incorrect syntax -- did you forget the context?\n";
75
2
20
        return undef;
76    }
77
78
36
297
    if ( @_ % 2 ) {
79
2
49
        warn "Incorrect syntax -- new() requires a hash\n";
80
2
32
        return undef;
81    }
82
83
34
587
    my %opts = @_;
84
34
513
    my $resp = Tivoli::AccessManager::Admin::Response->new();
85
86
34
368
    my $self = bless {}, $class;
87
88
34
440
    $self->{name} = $opts{name} || '';
89
34
368
    $self->{dn} = $opts{dn} || '';
90
34
368
    $self->{cn} = $opts{cn} || '';
91
34
360
    $self->{sn} = $opts{sn} || '';
92
34
211
    $self->{exist} = 0;
93
34
581
    $self->_userstore();
94
34
241
    $self->{context} = $cont;
95
96
34
863
    unless ( $self->{cn} ) {
97
11
293
        $self->{cn} = $1 if $self->{dn} =~ /^cn=(.+?),/;
98    }
99
100    # If the name was provided, call getuser to see if the user exists.
101
34
321
    if ( $self->{name} ) {
102
29
1635991
        my $rc = $self->user_get( $resp );
103
104
29
579
        if ( $rc ) {
105
8
256
            $self->{dn} = $self->user_getdn();
106
8
153
            $self->{cn} = $self->user_getcn();
107
8
132
            $self->{sn} = $self->user_getsn();
108
8
134
            $self->{exist} = 1;
109        }
110    }
111    elsif ( $self->{dn} ) {
112
4
273983
        my $rc = $self->user_getbydn( $resp );
113
4
125
        if ( $rc ) {
114
3
99
            $self->{name} = $self->user_getid();
115
3
53
            $self->{cn} = $self->user_getcn();
116
3
54
            $self->{sn} = $self->user_getsn();
117            # It is possible for getbydn to return a user in the LDAP who is
118            # not TAMified. This makes sure the discovered user is TAMified
119
3
171613
            $self->{exist} = $self->user_get($resp);
120        }
121    }
122
123
34
562
    return $self;
124}
125
126sub create {
127
33
1
471
    my $self = shift;
128
33
512
    my $resp = Tivoli::AccessManager::Admin::Response->new();
129
33
239
    my $gref = [];
130
131
33
328
    unless ( ref $self ) {
132
19
112
        my $pd = shift;
133
19
455
        unless ( defined($pd) and UNIVERSAL::isa($pd,'Tivoli::AccessManager::Admin::Context' ) ) {
134
3
35
            $resp->set_message("Incorrect syntax -- did you forget the context?");
135
3
38
            $resp->set_isok(0);
136
3
33
            return $resp;
137        }
138
16
161
        $self = new( $self, $pd, @_ );
139    }
140
141
30
828
    if ( @_ % 2 ) {
142
1
15
        $resp->set_message("Incorrect syntax -- create() requires a hash");
143
1
15
        $resp->set_isok(0);
144
1
8
        return $resp;
145    }
146
147
29
449
    my %opts = @_;
148
149
29
321
    if ( $self->{exist} ) {
150
7
106
        $resp->set_message( $self->{name} . " already exists" );
151
7
75
        $resp->set_iswarning(1);
152
7
67
        $resp->set_value( $self );
153
154
7
103
        return $resp;
155    }
156
157
22
176
    unless ( $self->{name} ) {
158
3
81
        $self->{name} = $opts{name} || '';
159    }
160
161
22
167
    unless ( $self->{dn} ) {
162
3
63
        $self->{dn} = $opts{dn} || '';
163    }
164
165
22
170
    unless ( $self->{cn} ) {
166
3
101
        $self->{cn} = $opts{cn} || '';
167    }
168
169
22
949
    unless ( $self->{sn} ) {
170
3
49
        $self->{sn} = $opts{sn} || '';
171    }
172
173
174
22
200
    $opts{password} ||= '';
175
22
272
    $opts{sso} = defined( $opts{sso} ) ? $opts{sso} : 0;
176
22
218
    $opts{nopwdpolicy} = defined( $opts{nopwdpolicy} ) ? $opts{nopwdpolicy} : 0;
177
22
162
    if ( defined( $opts{groups} ) ) {
178
3
63
        if (ref($opts{groups}) eq 'ARRAY') {
179
1
24
            $gref = $opts{groups};
180        }
181        elsif ( ref($opts{groups}) ) {
182
1
16
            $resp->set_message("Invalid group syntax -- it must be a string or an array ref");
183
1
14
            $resp->set_isok(0);
184
1
6
            return $resp;
185        }
186        else {
187
1
10
            push @$gref, $opts{groups};
188        }
189    }
190
21
347
    $opts{groups} = [] unless defined( $opts{groups} );
191
192
21
555
    if ( $self->{name} and $self->{dn} and $self->{sn} and $self->{cn} ) {
193
17
1604033
        my $rc = $self->user_create( $resp, $opts{password}, $gref,
194                                    $opts{sso}, $opts{nopwdpolicy});
195
17
578
        if ( $resp->isok ) {
196
15
147
            $self->{exist} = 1;
197
15
200
            $resp->set_value($self);
198        }
199    }
200    else {
201
4
68
        $resp->set_message("create: you must defined the userid, the DN, the CN and the SN");
202
4
52
        $resp->set_isok(0);
203    }
204
205
21
658
    return $resp;
206}
207
208sub delete {
209
25
1
230
    my $self = shift;
210
25
350
    my $resp = Tivoli::AccessManager::Admin::Response->new();
211
25
149
    my $registry = 0;
212
213
214
25
260
    if ( @_ == 1 ) {
215
4
21
        $registry = shift;
216    }
217    elsif ( @_ % 2 ) {
218
1
14
        $resp->set_message("Incorrect syntax -- delete needs a hash or just one parameter");
219
1
13
        $resp->set_isok(0);
220
1
11
        return $resp;
221    }
222    else {
223
20
181
        my %opts = @_;
224
20
232
        $registry = $opts{registry} || 0;
225    }
226
227
24
171
    unless ( $self->{exist} ) {
228
2
38
        $resp->set_message( "delete: " . $self->{name} . " doesn't exist" );
229
2
27
        $resp->set_isok(0);
230
231
2
18
        return $resp;
232    }
233
234
22
2117286
    my $rc = $self->user_delete($resp,$registry);
235
22
1111
    if ( $resp->isok ) {
236
21
279
        $resp->set_value( $rc );
237
21
284
        $self->{exist} = 0;
238    }
239
240
22
276
    return $resp;
241}
242
243sub description {
244
8
1
53
    my $self = shift;
245
8
104
    my $resp = Tivoli::AccessManager::Admin::Response->new();
246
247
8
72
    if ( $self->{exist} ) {
248
7
27
        my $desc;
249
250
7
89
        if ( @_ == 1 ) {
251
2
13
            $desc = shift;
252        }
253        elsif ( @_ % 2 ) {
254
1
10
            $resp->set_message("Invalid syntax");
255
1
11
            $resp->set_isok(0);
256
1
9
            return $resp;
257        }
258        elsif (@_) {
259
2
15
            my %opts = @_;
260
2
34
            $desc = $opts{description} || '';
261        }
262
263
6
34
        if ( defined $desc ) {
264
4
183585
            my $rc = $self->user_setdescription($resp, $desc);
265
4
102
            $resp->isok && $self->user_get($resp);
266        }
267
6
100
        if ( $resp->isok ) {
268
5
143
            my $rc = $self->user_getdescription;
269
5
82
            if ( defined $rc ) {
270
4
54
                $resp->set_value($rc);
271            }
272            else {
273
1
14
                $resp->set_message("Could not retrieve user's description");
274
1
13
                $resp->set_isok(0);
275            }
276        }
277    }
278    else {
279
1
14
        $resp->set_message( "The user does not yet exist" );
280
1
14
        $resp->set_isok(0);
281    }
282
283
7
64
    return $resp;
284}
285
286sub accexpdate {
287
8
1
93
    my $self = shift;
288
8
53
    my $lifetime = 0;
289
8
130
    my $resp = Tivoli::AccessManager::Admin::Response->new();
290
291
8
47
    my ($seconds,$unlimited,$unset,$rc);
292
8
84
    if ( @_ == 1 ) {
293
4
28
        $lifetime = shift;
294    }
295    elsif ( @_ % 2 ) {
296
1
13
        $resp->set_message("Invalid syntax");
297
1
14
        $resp->set_isok(0);
298
1
13
        return $resp;
299    }
300    elsif ( @_ ) {
301
2
20
        my %opts = @_;
302
2
35
        $lifetime = $opts{lifetime} || 0;
303    }
304    else {
305
1
7
        $lifetime = 0;
306    }
307
308
7
54
    if ( $lifetime ) {
309
5
94
        if ( $lifetime =~ /^\d+$/ ) {
310
1
3
            $unlimited = 0;
311
1
6
            $unset = 0;
312        }
313        elsif ( $lifetime eq 'unlimited' ) {
314
2
14
            ($unlimited,$unset,$lifetime) = (1,0,0);
315        }
316        elsif ( $lifetime eq 'unset' ) {
317
1
8
            ($unlimited,$unset,$lifetime) = (0,1,0);
318        }
319        else {
320
1
12
            $resp->set_message("The parameter must either be an integer, 'unset' or 'unlimited'");
321
1
10
            $resp->set_isok(0);
322
1
10
            return $resp;
323        }
324
4
240453
        $rc = $self->user_setaccexpdate( $resp,
325                                         $lifetime,
326                                         $unlimited,
327                                         $unset );
328
4
139
        $resp->isok && $self->user_get($resp);
329    }
330
6
116
    if ( $resp->isok ) {
331
5
258825
        ($seconds,$unlimited,$unset) = $self->user_getaccexpdate($resp);
332
5
197
        $resp->set_value( $unlimited ? "unlimited" : $unset ? "unset" : $seconds);
333    }
334
335
6
79
    return $resp;
336}
337
338sub disabletimeint {
339
8
1
75
    my $self = shift;
340
8
128
    my $resp = Tivoli::AccessManager::Admin::Response->new();
341
8
49
    my ($seconds,$disable,$unset,$rc);
342
343
8
135
    if ( @_ == 1 ) {
344
4
29
        $seconds = shift;
345    }
346    elsif ( @_ % 2 ) {
347
1
15
        $resp->set_message("Invalid syntax");
348
1
14
        $resp->set_isok(0);
349
1
13
        return $resp;
350    }
351    elsif ( @_ ) {
352
2
22
        my %opts = @_;
353
2
41
        $seconds = $opts{seconds} || '';
354    }
355    else {
356
1
7
        $seconds = '';
357    }
358
359
7
47
    if ( $seconds ) {
360
5
102
        if ( $seconds =~ /^\d+$/ ) {
361
1
4
            $disable = 0;
362
1
6
            $unset = 0;
363        }
364        elsif ($seconds eq 'disable') {
365
1
10
            ($disable,$unset,$seconds) = (1,0,0);
366        }
367        elsif ($seconds eq 'unset') {
368
2
16
            ($disable,$unset,$seconds) = (0,1,0);
369        }
370        else {
371
1
19
            $resp->set_message("The parameter must either be an integer, 'disable' or 'unset'");
372
1
20
            $resp->set_isok(0);
373
1
17
            return $resp;
374        }
375
376
4
248225
        $rc = $self->user_setdisabletimeint( $resp,
377                                             $seconds,
378                                             $disable,
379                                             $unset);
380
4
125
        $resp->isok && $self->user_get($resp);
381    }
382
6
122
    if ( $resp->isok ) {
383
5
288731
        ($seconds,$disable,$unset) = $self->user_getdisabletimeint( $resp );
384
5
210
        $resp->set_value( $disable ? "disable" : $unset ? "unset" : $seconds );
385    }
386
387
6
86
    return $resp;
388}
389
390sub maxlgnfails {
391
7
1
574
    my $self = shift;
392
7
122
    my $resp = Tivoli::AccessManager::Admin::Response->new();
393
7
38
    my ($failures,$unset,$rc);
394
395
7
97
    if ( @_ == 1 ) {
396
3
23
        $failures = shift;
397    }
398    elsif ( @_ % 2 ) {
399
1
19
        $resp->set_message("Invalid syntax");
400
1
15
        $resp->set_isok(0);
401
1
13
        return $resp;
402    }
403    elsif ( @_ ) {
404
2
32
        my %opts = @_;
405
2
42
        $failures = $opts{failures} || '';
406    }
407    else {
408
1
11
        $failures = '';
409    }
410
411
6
48
    if ( $failures ) {
412
4
75
        if ( $failures =~ /^\d+$/ ) {
413
1
8
            $unset = 0;
414        }
415        elsif ($failures eq 'unset') {
416
2
12
            $failures = 0;
417
2
11
            $unset = 1;
418        }
419        else {
420
1
13
            $resp->set_message("The parameter must either be an integer or 'unset'");
421
1
13
            $resp->set_isok(0);
422
1
9
            return $resp;
423        }
424
425
3
195663
        $rc = $self->user_setmaxlgnfails( $resp,
426                                          $failures,
427                                          $unset);
428
3
99
        $resp->isok && $self->user_get($resp);
429    }
430
5
113
    if ( $resp->isok ) {
431
4
237487
        ($failures,$unset) = $self->user_getmaxlgnfails( $resp );
432
4
150
        $resp->set_value($unset ? "unset" : $failures);
433    }
434
435
5
71
    return $resp;
436}
437
438sub maxpwdage {
439
7
1
41
    my $self = shift;
440
7
80
    my $resp = Tivoli::AccessManager::Admin::Response->new();
441
7
29
    my ($seconds,$unset,$rc);
442
443
7
67
    if ( @_ == 1 ) {
444
3
15
        $seconds = shift;
445    }
446    elsif ( @_ % 2 ) {
447
1
16
        $resp->set_message("Invalid syntax");
448
1
14
        $resp->set_isok(0);
449
1
8
        return $resp;
450    }
451    elsif ( @_ ) {
452
2
11
        my %opts = @_;
453
2
24
        $seconds = $opts{seconds} || '';
454    }
455    else {
456
1
9
        $seconds = '';
457    }
458
459
6
38
    if ( $seconds ) {
460
4
53
        if ( $seconds =~ /^\d+$/ ) {
461
1
4
            $unset = 0;
462        }
463        elsif ($seconds eq 'unset') {
464
2
9
            $seconds = 0;
465
2
7
            $unset = 1;
466        }
467        else {
468
1
11
            $resp->set_message("The parameter must either be an integer or 'unset'");
469
1
8
            $resp->set_isok(0);
470
1
7
            return $resp;
471        }
472
473
3
197361
        $rc = $self->user_setmaxpwdage( $resp,
474                                        $seconds,
475                                        $unset );
476
3
71
        $resp->isok && $self->user_get($resp);
477    }
478
5
64
    if ( $resp->isok ) {
479
4
228369
        ($seconds,$unset) = $self->user_getmaxpwdage( $resp );
480
4
123
        $resp->set_value($unset ? "unset" : $seconds);
481    }
482
483
5
50
    return $resp;
484}
485
486sub maxpwdrepchars {
487
7
1
44
    my $self = shift;
488
7
109
    my $resp = Tivoli::AccessManager::Admin::Response->new();
489
7
25
    my ($chars,$unset,$rc);
490
491
7
67
    if ( @_ == 1 ) {
492
3
17
        $chars = shift;
493    }
494    elsif ( @_ % 2 ) {
495
1
26
        $resp->set_message("Invalid syntax");
496
1
8
        $resp->set_isok(0);
497
1
11
        return $resp;
498    }
499    elsif ( @_ ) {
500
2
17
        my %opts = @_;
501
2
28
        $chars = $opts{chars} || '';
502    }
503    else {
504
1
5
        $chars = '';
505    }
506
507
6
36
    if ( $chars ) {
508
4
53
        if ( $chars =~ /^\d+$/ ) {
509
1
7
            $unset = 0;
510        }
511        elsif ($chars eq 'unset') {
512
2
12
            $chars = 0;
513
2
6
            $unset = 1;
514        }
515        else {
516
1
12
            $resp->set_message("The parameter must either be an integer or 'unset'");
517
1
14
            $resp->set_isok(0);
518
1
10
            return $resp;
519        }
520
3
378107
        $rc = $self->user_setmaxpwdrepchars( $resp,
521                                                $chars,
522                                                $unset );
523
3
78
        $resp->isok && $self->user_get($resp);
524    }
525
5
72
    if ( $resp->isok ) {
526
4
199544
        ($chars,$unset) = $self->user_getmaxpwdrepchars( $resp );
527
4
103
        $resp->set_value($unset ? "unset" : $chars);
528    }
529
530
5
50
    return $resp;
531}
532
533sub minpwdalphas {
534
7
1
40
    my $self = shift;
535
7
71
    my $resp = Tivoli::AccessManager::Admin::Response->new();
536
7
24
    my ($chars,$unset,$rc);
537
538
7
63
    if ( @_ == 1 ) {
539
3
16
        $chars = shift;
540    }
541    elsif ( @_ % 2 ) {
542
1
6
        $resp->set_message("Invalid syntax");
543
1
10
        $resp->set_isok(0);
544
1
5
        return $resp;
545    }
546    elsif ( @_ ) {
547
2
13
        my %opts = @_;
548
2
23
        $chars = $opts{chars} || '';
549    }
550    else {
551
1
5
        $chars = '';
552    }
553
554
6
32
    if ( $chars ) {
555
4
47
        if ( $chars =~ /^\d+$/ ) {
556
1
6
            $unset = 0;
557        }
558        elsif ($chars eq 'unset') {
559
2
7
            $chars = 0;
560
2
10
            $unset = 1;
561        }
562        else {
563
1
13
            $resp->set_message("The parameter must either be an integer or 'unset'");
564
1
12
            $resp->set_isok(0);
565
1
8
            return $resp;
566        }
567
3
222870
        $rc = $self->user_setminpwdalphas( $resp,
568                                           $chars,
569                                           $unset );
570
3
62
        $resp->isok && $self->user_get($resp);
571    }
572
5
55
    if ( $resp->isok ) {
573
4
214760
        ($chars,$unset) = $self->user_getminpwdalphas( $resp );
574
4
97
        $resp->set_value( $unset ? "unset" : $chars );
575    }
576
577
5
50
    return $resp;
578}
579
580sub minpwdnonalphas {
581
7
1
44
    my $self = shift;
582
7
82
    my $resp = Tivoli::AccessManager::Admin::Response->new();
583
7
29
    my ($chars,$unset,$rc);
584
585
7
69
    if ( @_ == 1 ) {
586
3
16
        $chars = shift;
587    }
588    elsif ( @_ % 2 ) {
589
1
7
        $resp->set_message("Invalid syntax");
590
1
7
        $resp->set_isok(0);
591
1
6
        return $resp;
592    }
593    elsif ( @_ ) {
594
2
17
        my %opts = @_;
595
2
30
        $chars = $opts{chars} || '';
596    }
597    else {
598
1
8
        $chars = '';
599    }
600
601
6
35
    if ( $chars ) {
602
4
55
        if ( $chars =~ /^\d+$/ ) {
603
1
6
            $unset = 0;
604        }
605        elsif ($chars eq 'unset') {
606
2
7
            $chars = 0;
607
2
12
            $unset = 1;
608        }
609        else {
610
1
12
            $resp->set_message("The parameter must either be an integer or 'unset'");
611
1
10
            $resp->set_isok(0);
612
1
10
            return $resp;
613        }
614
3
153836
        $rc = $self->user_setminpwdnonalphas( $resp,
615                                              $chars,
616                                              $unset );
617
3
67
        $resp->isok && $self->user_get($resp);
618
619    }
620
5
62
    if ( $resp->isok ) {
621
4
204391
        ($chars,$unset) = $self->user_getminpwdnonalphas( $resp );
622
4
101
        $resp->set_value($unset ? "unset" : $chars);
623    }
624
625
5
43
    return $resp;
626}
627
628sub minpwdlen {
629
7
1
42
    my $self = shift;
630
7
86
    my $resp = Tivoli::AccessManager::Admin::Response->new();
631
7
30
    my ($chars,$unset,$rc);
632
633
7
67
    if ( @_ == 1 ) {
634
3
18
        $chars = shift;
635    }
636    elsif ( @_ % 2 ) {
637
1
16
        $resp->set_message("Invalid syntax");
638
1
14
        $resp->set_isok(0);
639
1
12
        return $resp;
640    }
641    elsif ( @_ ) {
642
2
16
        my %opts = @_;
643
2
28
        $chars = $opts{chars} || '';
644    }
645    else {
646
1
5
        $chars = '';
647    }
648
649
6
33
    if ( $chars ) {
650
4
50
        if ( $chars =~ /^\d+$/ ) {
651
1
5
            $unset = 0;
652        }
653        elsif ($chars eq 'unset') {
654
2
9
            $chars = 8;
655
2
8
            $unset = 1;
656        }
657        else {
658
1
10
            $resp->set_message("The parameter must either be an integer or 'unset'");
659
1
8
            $resp->set_isok(0);
660
1
6
            return $resp;
661        }
662
3
163495
        $rc = $self->user_setminpwdlen( $resp,
663                                        $chars,
664                                        $unset );
665
3
68
        $resp->isok && $self->user_get($resp);
666    }
667
5
76
    if ( $resp->isok ) {
668
4
242340
        ($chars,$unset) = $self->user_getminpwdlen( $resp );
669
4
111
        $resp->set_value($unset ? "unset" : $chars);
670    }
671
672
5
54
    return $resp;
673}
674
675sub max_concur_session {
676
10
1
62
    my $self = shift;
677
10
125
    my $resp = Tivoli::AccessManager::Admin::Response->new();
678
10
45
    my ($session,$unset,$unlimited,$displace,$rc);
679
680
10
83
    if ( @_ == 1 ) {
681
6
32
        $session = shift;
682    }
683    elsif ( @_ % 2 ) {
684
1
11
        $resp->set_message("Invalid syntax");
685
1
7
        $resp->set_isok(0);
686
1
6
        return $resp;
687    }
688    elsif ( @_ ) {
689
2
17
        my %opts = @_;
690
2
30
        $session = $opts{session} || '';
691    }
692    else {
693
1
6
        $session = '';
694    }
695
696
9
51
    if ( $session ) {
697
7
103
        if ( $session =~ /^\d+$/ ) {
698
1
8
            ($unset,$unlimited,$displace) = (0,0,0);
699        }
700        elsif ($session eq 'displace') {
701
1
4
            ($session,$unset,$unlimited,$displace) = (0,0,0,1);
702        }
703        elsif ($session eq 'unlimited') {
704
1
7
            ($session,$unset,$unlimited,$displace) = (0,0,1,0);
705        }
706        elsif ($session eq 'unset') {
707
3
18
            ($session,$unset,$unlimited,$displace) = (0,1,0,0);
708        }
709        else {
710
1
12
            $resp->set_message("The parameter must be either an integers, 'displace', 'unlimited' or 'unset'");
711
1
10
            $resp->set_isok(0);
712
1
9
            return $resp;
713        }
714
715
6
302247
        $rc = $self->user_setmaxconcurwebsess( $resp,
716                                                  $session,
717                                                  $displace,
718                                                  $unlimited,
719                                                  $unset,
720                                                 );
721
6
145
        $resp->set_value($rc);
722
723    }
724
8
84
    if ( $resp->isok ) {
725
7
38
        my $retval;
726
7
344903
        ($session,$displace,$unlimited,$unset) = $self->user_getmaxconcurwebsess( $resp );
727
728
7
105
        if ($unset) {
729
4
29
            $retval = 'unset';
730        }
731        elsif ($displace) {
732
1
10
            $retval = 'displace';
733        }
734        elsif ($unlimited) {
735
1
7
            $retval = 'unlimited';
736        }
737        else {
738
1
10
            $retval = $session;
739        }
740
7
107
        $resp->set_value($retval);
741    }
742
743
8
92
    return $resp;
744}
745
746sub pwdspaces {
747
7
1
43
    my $self = shift;
748
7
80
    my $resp = Tivoli::AccessManager::Admin::Response->new();
749
7
33
    my ($allowed,$unset,$rc);
750
751
7
59
    if ( @_ == 1 ) {
752
3
15
        $allowed = shift;
753    }
754    elsif ( @_ % 2 ) {
755
1
11
        $resp->set_message("Invalid syntax");
756
1
10
        $resp->set_isok(0);
757
1
9
        return $resp;
758    }
759    elsif ( @_ ) {
760
2
16
        my %opts = @_;
761
2
26
        $allowed = $opts{allowed} || '';
762    }
763    else {
764
1
5
        $allowed = '';
765    }
766
767
6
35
    if ( $allowed ) {
768
4
53
        if ($allowed =~ /^\d+$/) {
769
1
5
            $unset = 0;
770        }
771        elsif ( $allowed eq 'unset' ) {
772
2
8
            $allowed = 0;
773
2
9
            $unset = 1;
774        }
775        else {
776
1
13
            $resp->set_message("The parameter must either be an integer or 'unset'");
777
1
14
            $resp->set_isok(0);
778
1
8
            return $resp;
779        }
780
3
146552
        $rc = $self->user_setpwdspaces( $resp,
781                                        $allowed,
782                                       $unset );
783
3
67
        $resp->isok && $self->user_get($resp);
784    }
785
5
64
    if ( $resp->isok ) {
786
4
199744
        ($allowed,$unset) = $self->user_getpwdspaces( $resp );
787
4
100
        $resp->set_value($unset ? "unset" : $allowed );
788    }
789
790
5
48
    return $resp;
791}
792
793sub tod {
794
10
1
103
    my $self = shift;
795
10
144
    my $resp = Tivoli::AccessManager::Admin::Response->new();
796
10
51
    my ( $days, $start, $end, $reference, $unset, $rc );
797
10
43
    my (@list, %rc );
798
799
10
84
    if ( @_ % 2 ) {
800
1
11
        $resp->set_message("Invalid syntax");
801
1
10
        $resp->set_isok(0);
802
1
9
        return $resp;
803    }
804
9
134
    my %opts = @_;
805
806
9
86
    $reference = $opts{reference} || '';
807
808
9
180
    if ( $opts{days} ) {
809
8
51
        $reference = $reference eq 'UTC';
810
811
8
118
        if ( $opts{days} ne 'unset' ) {
812
7
79
            if ( ref($opts{days}) ) {
813
5
48
                $days = _listtotod( $opts{days} )
814            }
815            else {
816
2
23
                if ( $opts{days} > 127 ) {
817
1
10
                    $resp->set_message( "days bitmask > 127");
818
1
5
                    $resp->set_isok(0);
819
1
11
                    return $resp;
820                }
821
1
10
                $days = $opts{days};
822            }
823
6
56
            $start = _miltomin( $opts{start} );
824
6
44
            $end = _miltomin( $opts{end} );
825
6
33
            $unset = 0;
826        }
827        else {
828
1
9
            $days = $start = $end = 0;
829
1
5
            $unset = 1;
830        }
831
832
7
389263
        $self->user_settodaccess( $resp,
833                                  $days,
834                                  $start,
835                                  $end,
836                                  $reference,
837                                  $unset );
838
7
220
        $resp->isok && $self->user_get($resp);
839    }
840
8
192
    if ( $resp->isok ) {
841
7
410697
        @list = $self->user_gettodaccess( $resp );
842
7
137
        if ( $list[-1] ) {
843
2
20
            $rc{days} = 0;
844
2
14
            $rc{start} = 0;
845
2
14
            $rc{end} = 0;
846
2
22
            $rc{reference} = 'local';
847
2
11
            $rc{unset} = 1;
848        }
849        else {
850
5
76
            $rc{days} = [ _todtolist($list[0]) ];
851
5
60
            $rc{start} = _mintomil( $list[1]);
852
5
50
            $rc{end} = _mintomil( $list[2]);
853
5
60
            $rc{reference} = $list[3] ? 'UTC' : 'local';
854        }
855
856
7
135
        $resp->set_value( \%rc );
857    }
858
8
164
    return $resp;
859}
860
861sub list {
862
8
1
55
    my $class = shift;
863
8
33
    my $pd;
864
8
99
    my $resp = Tivoli::AccessManager::Admin::Response->new();
865
866    # I want this to be called as either Tivoli::AccessManager::Admin::User->list or
867    # $self->list
868
8
52
    if ( ref($class) ) {
869
1
7
        $pd = $class->{context};
870    }
871    else {
872
7
31
        $pd = shift;
873
7
148
        unless ( defined($pd) and UNIVERSAL::isa($pd,'Tivoli::AccessManager::Admin::Context' ) ) {
874
2
17
            $resp->set_message("Incorrect syntax -- did you forget the context?");
875
2
18
            $resp->set_isok(0);
876
2
9
            return $resp;
877        }
878    }
879
880
6
60
    if ( @_ % 2 ) {
881
1
13
        $resp->set_message("Invalid syntax");
882
1
9
        $resp->set_isok(0);
883
1
9
        return $resp;
884    }
885
5
57
    my %opts = @_;
886
887
5
54
    $opts{maxreturn} = 0 unless defined( $opts{maxreturn} );
888
5
53
    $opts{pattern} = '*' unless defined( $opts{pattern} );
889
5
51
    $opts{bydn} = 0 unless defined( $opts{bydn} );
890
891
892
5
262851
    my @rc = sort $opts{bydn} ? user_listbydn( $pd, $resp,
893                                          $opts{pattern},
894                                    $opts{maxreturn} ) :
895                           user_list( $pd, $resp,
896                                      $opts{pattern},
897                                      $opts{maxreturn} );
898
5
163
    $resp->isok() && $resp->set_value( \@rc );
899
5
107
    return $resp;
900}
901
902sub groups {
903
14
1
277
    my $self = shift;
904
14
72
    my (@groups, $group);
905
14
202
    my $resp = Tivoli::AccessManager::Admin::Response->new;
906
14
91
    my @dne = ();
907
908
14
115
    if ( @_ % 2 ) {
909
1
11
        $resp->set_message("Invalid syntax");
910
1
10
        $resp->set_isok(0);
911
1
10
        return $resp;
912    }
913
13
105
    my %opts = @_;
914
13
108
    if ( defined( $opts{remove} ) ) {
915
4
4
16
34
        for my $grp ( @{$opts{remove}} ) {
916
12
101
            if ( ref $grp ) {
917
5
29
                $group = $grp;
918            }
919            else {
920
7
107
                $group = Tivoli::AccessManager::Admin::Group->new( $self->{context}, name => $grp );
921            }
922
12
174
            my $gname = $group->name;
923
924
12
130
            if ( $group->exist ) {
925
11
187
                $resp = $group->members( remove => [ $self->{name} ] );
926
11
105
                return $resp unless $resp->isok;
927            }
928            else {
929
1
35
                push @dne, $gname;
930            }
931        }
932    }
933
934
12
107
    if ( defined( $opts{add} ) ) {
935
4
4
19
23
        for my $grp ( @{$opts{add}} ) {
936
12
120
            if ( ref $grp ) {
937
5
35
                $group = $grp;
938            }
939            else {
940
7
112
                $group = Tivoli::AccessManager::Admin::Group->new( $self->{context}, name => $grp );
941            }
942
12
208
            my $gname = $group->name;
943
944
12
143
            if ( $group->exist ) {
945
11
228
                $resp = $group->members( add => [ $self->{name} ] );
946
11
168
                return $resp unless $resp->isok;
947            }
948            else {
949
1
34
                push @dne, $gname;
950            }
951        }
952    }
953
954
12
970870
    @groups = $self->user_getmemberships( $resp );
955
12
431
    $resp->isok and $resp->set_value(\@groups);
956
12
118
    if ( @dne ) {
957
2
64
        $resp->set_message("The following groups did not exist: " . join(",",@dne));
958
2
916
        $resp->set_iswarning(1);
959    }
960
961
12
195
    return $resp;
962}
963
964sub userimport {
965
16
1
226
    my $self = shift;
966
16
214
    my $resp = Tivoli::AccessManager::Admin::Response->new();
967
968
16
144
    unless ( ref $self ) {
969
8
48
        my $pd = shift;
970
8
199
        unless ( defined($pd) and UNIVERSAL::isa($pd,'Tivoli::AccessManager::Admin::Context' ) ) {
971
2
28
            $resp->set_message("Incorrect syntax -- did you forget the context?");
972
2
21
            $resp->set_isok(0);
973
2
22
            return $resp;
974        }
975
976
6
71
        if ( @_ % 2 ) {
977
1
15
            $resp->set_message("Invalid syntax");
978
1
13
            $resp->set_isok(0);
979
1
11
            return $resp;
980        }
981
5
43
        $self = new( $self, $pd, @_ );
982    }
983
984
13
286
    if ( @_ % 2 ) {
985
1
7
        $resp->set_message("Invalid syntax");
986
1
7
        $resp->set_isok(0);
987
1
6
        return $resp;
988    }
989
12
128
    my %opts = @_;
990
991
12
109
    if ( $self->{exist} ) {
992
2
23
        $resp->set_message("Cannot create a user that already exists");
993
2
21
        $resp->set_isok(0);
994
2
16
        return $resp;
995    }
996
997
10
86
    unless ( $self->{name} ) {
998
3
68
        $self->{name} = $opts{name} || "";
999    }
1000
1001
10
82
    unless ( $self->{dn} ) {
1002
3
56
        $self->{dn} = $opts{dn} || "";
1003    }
1004
1005
10
132
    $opts{sso} = 0 unless defined($opts{sso});
1006
1007
10
146
    if ( $self->{name} and $self->{dn} ) {
1008
6
425470
        my $rc = $self->user_import( $resp, "", $opts{sso} );
1009
6
167
        if ( $resp->isok() ) {
1010
6
414928
            my $user = $self->user_get( $resp );
1011
6
213
            $self->{dn} = $self->user_getdn();
1012
6
130
            $self->{name} = $self->user_getid();
1013
6
75
            $self->{cn} = $self->user_getcn();
1014
6
71
            $self->{sn} = $self->user_getsn();
1015
1016
6
45
            $self->{exist} = 1;
1017
6
65
            if ( defined($opts{groups}) ) {
1018
1
12
                $resp = $self->groups( add => $opts{groups} );
1019
1
16
                return $resp unless $resp->isok;
1020            }
1021
6
113
            $resp->isok and $resp->set_value( $self );
1022        }
1023    }
1024    elsif ( $self->{dn} ) {
1025
2
37
        $resp->set_message("You must specify the user's name");
1026
2
31
        $resp->set_isok(0);
1027    }
1028    else {
1029
2
27
        $resp->set_message("You must specify the user's dn");
1030
2
23
        $resp->set_isok(0);
1031    }
1032
1033
10
159
    return $resp;
1034}
1035
1036sub accountvalid {
1037
6
1
42
    my $self = shift;
1038
6
73
    my $resp = Tivoli::AccessManager::Admin::Response->new();
1039
6
22
    my ($rc,$valid);
1040
1041
6
70
    if ( @_ == 1 ) {
1042
2
12
        $valid = shift;
1043    }
1044    elsif ( @_ % 2 ) {
1045
1
11
        $resp->set_message("Invalid syntax");
1046
1
10
        $resp->set_isok(0);
1047
1
9
        return $resp;
1048    }
1049    elsif ( @_ ) {
1050
2
21
        my %opts = @_;
1051
2
23
        $valid = $opts{valid};
1052    }
1053
1054    # Set
1055
5
29
    if ( defined($valid) ) {
1056
3
147688
        $rc = $self->user_setaccountvalid( $resp, $valid );
1057
3
95
        $resp->isok && $self->user_get($resp);
1058    }
1059
1060
5
82
    if ( $resp->isok ) {
1061
4
130
        $rc = $self->user_getaccountvalid();
1062
4
38
        $resp->set_value( $rc );
1063    }
1064
1065
5
51
    return $resp;
1066}
1067
1068sub passwordvalid {
1069
5
1
30
    my $self = shift;
1070
5
56
    my $resp = Tivoli::AccessManager::Admin::Response->new();
1071
5
17
    my ($rc,$valid);
1072
1073
5
84
    if ( @_ == 1 ) {
1074
1
5
        $valid = shift;
1075    }
1076    elsif ( @_ % 2 ) {
1077
1
28
        $resp->set_message("Invalid syntax");
1078
1
6
        $resp->set_isok(0);
1079
1
11
        return $resp;
1080    }
1081    elsif ( @_ ) {
1082
2
20
        my %opts = @_;
1083
2
20
        $valid = $opts{valid};
1084    }
1085
1086
1087    # 0 is a valid input value. I need to test for definedness
1088
4
29
    if ( defined($valid) ) {
1089
2
101535
        $rc = $self->user_setpasswordvalid( $resp, $valid );
1090
2
61
        $resp->isok && $self->user_get($resp);
1091    }
1092
4
64
    if ( $resp->isok ) {
1093
4
125
        $rc = $self->user_getpasswordvalid();
1094
4
44
        $resp->set_value( $rc );
1095    }
1096
1097
4
22
    return $resp;
1098}
1099
1100sub ssouser {
1101
5
1
43
    my $self = shift;
1102
5
77
    my $resp = Tivoli::AccessManager::Admin::Response->new();
1103
5
25
    my ($rc,$sso);
1104
1105
5
79
    if ( @_ == 1 ) {
1106
1
11
        $sso = shift;
1107    }
1108    elsif ( @_ % 2 ) {
1109
1
7
        $resp->set_message("Invalid ssouser syntax");
1110
1
7
        $resp->set_isok(0);
1111
1
5
        return $resp;
1112    }
1113    elsif ( @_ ) {
1114
2
15
        my %opts = @_;
1115
2
44
        $sso = $opts{sso} || 0;
1116    }
1117
1118    # Set
1119
4
35
    if ( defined($sso) ) {
1120
3
167028
        $rc = $self->user_setssouser( $resp, $sso );
1121
3
93
        $resp->isok && $self->user_get($resp);
1122    }
1123
4
98
    if ( $resp->isok ) {
1124
4
160
        $rc = $self->user_getssouser();
1125
4
54
        $resp->set_value( $rc );
1126    }
1127
1128
4
50
    return $resp;
1129}
1130
1131sub password {
1132
5
1
37
    my $self = shift;
1133
5
66
    my $resp = Tivoli::AccessManager::Admin::Response->new();
1134
5
27
    my ($password,$rc);
1135
1136
5
62
    if ( @_ == 1 ) {
1137
2
15
        $password = shift;
1138    }
1139    elsif ( @_ % 2 ) {
1140
1
8
        $resp->set_message("Invalid password syntax");
1141
1
11
        $resp->set_isok(0);
1142
1
8
        return $resp;
1143    }
1144    elsif ( @_ ) {
1145
1
9
        my %opts = @_;
1146
1
13
        $password = $opts{password};
1147    }
1148
1149    # Set
1150
4
22
    if ( defined($password)) {
1151
3
224701
        $rc = $self->user_setpassword( $resp, $password );
1152
3
109
        $resp->set_value( $rc );
1153    }
1154    else {
1155
1
10
        $resp->set_message("There is no passwordget!");
1156
1
11
        $resp->set_isok(0);
1157    }
1158
1159
4
42
    return $resp;
1160}
1161
1162sub DESTROY {
1163
34
333
    my $self = shift;
1164
1165
34
919
    $self->_userfree;
1166}
1167
1168
4
1
140
sub exist { $_[0]->{exist} }
1169
5
1
84
sub name { $_[0]->{name} }
1170
1
1
26
sub cn { $_[0]->{cn} }
1171
1
1
23
sub dn { $_[0]->{dn} }
11721;
1173
1174 - 1618
=head1 NAME

Tivoli::AccessManager::Admin::User

=head1 SYNOPSIS

  use Tivoli::AccessManager::Admin

  my $pd = Tivoli::AccessManager::Admin->new( password => 'N3ew0nk' );
  my (@users,$resp);

  # Lets see who is there
  $resp = Tivoli::AccessManager::Admin::User->list( $pd, pattern => "luser*", maxreturn => 0 );
  print join("\n", $resp->value);

  # Lets search by DN instead
  $resp = Tivoli::AccessManager::Admin::User->list( $pd, pattern => "luser*", maxreturn => 0, bydn => 1 );
  print join("\n", $resp->value);

  # Lets create three new users, the easy way
  for my $i ( 0 .. 2 ) {
      my $name = sprintf "luser%02d", $i;
      $resp = Tivoli::AccessManager::Admin::User->create( $pd, name => $name,
	  			 dn => "cn=$name,ou=people,o=rox,c=us",
      				 sn => "Luser",
				 cn => "$name",
			         password => 'neeWonk');
      $users[$i] = $resp->value if $resp->isok;

      # Mark the account valid
      $resp = $users[$i]->accountvalid(1);
      # But force them to change the password on login
      $resp = $users[$i]->passwordvalid(0);
  }
  # A slightly different way to create a user
  push @users, Tivoli::AccessManager::Admin::User->new( $pd, name => 'luser03',
  				    dn => 'cn=luser03,ou=people,o=rox,c=us',
				    sn => 'Luser',
				    cn => 'luser03' );
  $resp = $users[-1]->create( password => 'Wonknee' );

  # Oops.  That last one was a mistake
  $resp = $users[-1]->delete;

  # Oops.  Deleting luser03 was a mistake.  Good thing we didn't remove her
  # from the registry
  $resp = $users[-1]->userimport;
  $resp = $users[-1]->password("Fjord!");

  # Nah.  Delete luser03 completely.
  $resp = $users[-1]->delete(1);

  # Hmm, lets put luser00 in a few groups
  $resp = $users[0]->groups( groups => [qw/sheep coworker/] );

=head1 DESCRIPTION

L<Tivoli::AccessManager::Admin::User> implements the User portion of the TAM API.  There is a fair
amount of overlap between L<Tivoli::AccessManager::Admin::User> and
L<Tivoli::AccessManager::Admin::Context>.  Since I am a lazy POD writer, I
will refer you to that FM when appropriate.

=head1 CONSTRUCTOR

=head2 new( PDADMIN[, name =E<gt> NAME, dn =E<gt> DN, cn =E<gt> CN, sn =E<gt> SN] )

Creates a blessed L<Tivoli::AccessManager::Admin::User> object.  As with everything else, you will need
to destroy the object if you want to change the context.

=head3 Parameters

=over 4

=item PDADMIN

An initialized L<Tivoli::AccessManager::Admin::Context> object.  This is the only required
parameter.

=item name =E<gt> NAME

The user's name, aka, the userid.  If this parameter is provided, L</"new"> will
try to determine if the user is already known to TAM.  If the user is,
all the fields ( cn, sn and dn ) will be retrieved from TAM.

=item dn =E<gt> DN

The user's DN.  If this value is provided (but L</"name"> is not), L</"new">
will look to see if the user is already defined.  If the user is, the other
fields (name, cn and sn) will be retrieved from TAM.

=item cn =E<gt> CN

The user's common name.  Nothing special happens if you provide the cn.

=item sn =E<gt> SN

The user's surname.  There is nothing special about this parameter either.

=back

=head3 Returns

A fully blessed L<Tivoli::AccessManager::Admin::User> object, with an embedded context.

=head1 CLASS METHODS

Class methods behave like instance methods -- they return
L<Tivoli::AccessManager::Admin::Response> objects.

=head2 list(PDADMIN [,maxreturn =E<gt> N, pattern =E<gt> STRING, bydn => 1])

Lists some subset of the TAM users.  There is no export available -- it would
quickly become gruesome with all the other module's lists.

=head3 Parameters

=over 4

=item PDADMIN

A fully blessed L<Tivoli::AccessManager::Admin::Context> object.  Since this is a class method,
and L<Tivoli::AccessManager::Admin::Context> objects are stored in the instances, you must
provide it.

=item maxreturn =E<gt> N

The number of users to return from the query.  This will default to 0, which
means all users matching the pattern.  Depending on how your LDAP is
configured, this may cause issues.

=item pattern =E<gt> STRING

The pattern to search on.  The standard rules for TAM searches apply -- * and
? are legal wild cards.  If not specified, it will default to *, which may
cause issues with your LDAP.  

=item bydn => 1

Changes the search from UID to DN.  Do be aware that this will return all the
inetOrgPerson objects in the LDAP, not just the TAMified users.

=back

=head3 Returns

The resulting list of users.

=head1 METHODS

All of the methods return a L<Tivoli::AccessManager::Admin::Response> object.  See the
documentation for that module on how to coax the values out.

The methods, for the most part, follow the same pattern.  If the optional
parameters are sent, it has the effect of setting the attributes.  All
methods calls will embed the results of a 'get' in the
L<Tivoli::AccessManager::Admin::Response> object.

=head2 create( password =E<gt> 'password'[, sso =E<gt> 0|1, nopwdpolicy =E<gt> 0|1, groups =E<gt> [qw/list of groups/][, name =E<gt> NAME, dn =E<gt> DN, cn =E<gt> CN, sn =E<gt> SN] )

Crikey.  That's an awful number of options, isn't it?  L</"create">, as you
might suspect, creates a user in TAM.  You can call L</"create"> instead of
L</"new"> and retrieve the L<Tivoli::AccessManager::Admin::User> object out of the Response object.

=head3 Parameters

=over 4

=item password =E<gt> 'password'

The new user's password.  This is the only required parameter.

=item sso =E<gt> 0|1

Controls if the user is created as a GSO user.  It defaults to false.

=item nopwdpolicy =E<gt> 0|1

Determines if the password policy is ignored when the user is created.
Defaults to false -- which is to say the default password policy will be
enforced.

=item groups =E<gt> [qw/list of a groups/]

A reference to an array containing the list of groups to which the user will
be added upon creation.  Defaults to the empty list.

=item name =E<gt> NAME

=item dn   =E<gt> DN

=item cn   =E<gt> CN

=item sn   =E<gt> SN

These are the same as defined in L</"new"> and each one is required only if
you did not provide it to L</"new"> or if you are calling L</"create"> instead of
L</"new">.

=back

=head3 Returns

The success or failure of the operation if L</"new"> was used, the new
L<Tivoli::AccessManager::Admin::User> object if not.  If the name, the DN, the CN and the SN are not
present, you will get an error message.

=head2 userimport([name =E<gt> NAME, dn =E<gt> DN, groups =E<gt> [qw/list of groups], sso =E<gt> 0|1)

"TAMifies" an existing user in the LDAP.  I would have loved to simply name
this import, but that had some very unfortunate side affects.  As with
L</"create">, you can call this method to initialize the L<Tivoli::AccessManager::Admin::User> object.

=head3 Parameters

=over 4

=item name =E<gt> NAME

The user's ID.  This is optional if you provided it to L</"new">.

=item dn =E<gt> DN

The user's DN.  This too is optional if you provided it to L</"new">.

=item groups =E<gt> [ qw/ list of groups/ ]

The groups the imported user is to be granted membership.  

=item sso =E<gt> 0 | 1

Import the user as a GSO user or not.  Defaults to "not".

=back

=head3 Returns

The success of the operation.  If you called L</"userimport"> instead of
L</"new">, you will get the L<Tivoli::AccessManager::Admin::User> object.

=head2 delete(0|1)

Deletes the user from TAM.

=head3 Parameters

=over 4

=item 0 | 1

Controls deleting the user from the registry.  This is an optional parameter
and will default to 0.

=back

=head3 Returns

The result of the operation

=head2 groups([ remove =E<gt> [qw/list of groups/], add =E<gt> [qw/list of groups/] ] )

Adds the user to the listed groups, removes them from another list or simply
returns the user's groups.

=head3 Parameters

=over 4

=item add =E<gt> [ qw/ list of groups/ ]

The list of groups to which the user will be added.

=item remove =E<gt> [ qw/ list of groups/ ]

The list of groups from which the user will be removed.  If both the add and
the remove tag are provided, the removes are processed first.

=back

=head3 Returns

The user's group memberships after the removes and adds are processed.  If
some of the specified groups do not exist, they will be listed in the error
message from the L<Tivoli::AccessManager::Admin::Response> object and the iswarning flag will be
set.  I wish I had a better way of returning interesting error info.

=head2 accountvalid( 0|1 )

Marks the user's account valid or not

=head3 Parameters

=over 4

=item 0|1

0 sets the account invalid, 1 sets it valid.

=back

=head3 Returns

1 if the account is valid, 0 if not.

=head2 password( STR )

Changes the user's password to the specified value

=head3 Parameters

=over 4

=item STR

The new password

=back

=head3 Returns

The success of the operation.  Kindly note that there is no get password
function

=head2 description( STR )

Changes the user's description to the specified value

=head3 Parameters

=over 4

=item STR

The new description

=back

=head3 Returns

The user's description.

=head2 passwordvalid( 0|1 )

Marks the user's password valid or not

=head3 Parameters

=over 4

=item 0|1

0 sets the password invalid, 1 sets it valid.

=back

=head3 Returns

1 if the password is valid, 0 if not.

=head2 ssouser( 0|1 )

Marks the user as a GSO enabled user.

=head3 Parameters

=over 4

=item 0|1

Disable or enable GSO for the user, respectively.

=back

=head3 Returns

1 if the user is GSO enabled, 0 otherwise.

=head2 exist

Returns true if the user is known to TAM.

=head2 name

Returns the user's ID, if known.

=head2 accexpdate

=head2 disabletimeint

=head2 maxlgnfails

=head2 tod

=head2 maxpwdage

=head2 maxpwdrepchars

=head2 minpwdalphas

=head2 minpwdnonalphas

=head2 minpwdlen

=head2 pwdspaces

=head2 max_concur_session

These are identical to the same named functions in L<Tivoli::AccessManager::Admin::Context>.
See that very fine manual for documentation.  I will repeat one caveat here.
If you perform a get on a non-existent user, the functions will not return an
error.  No idea why not.

=head1 TODO

The interface to accexpdate blows chunketh.  It needs to become significantly
smarter -- I want it to be able to accept:
   10 days from now ( which would be 11/27/2004 as of this note )
   11/27/2004-12:00:00
   86400 * 10
   1101588906
and each one of those should do the same thing.

=head1 ACKNOWLEDGEMENTS

See L<Tivoli::AccessManager::Admin> for the list.  This was not possible without the help of a
bunch of people smarter than I.

=head1 BUGS

Should L</"list"> return a list of names, or a list of L<Tivoli::AccessManager::Admin::User>
objects? 

=head1 AUTHOR

Mik Firestone E<lt>mikfire@gmail.comE<gt>

=head1 COPYRIGHT

Copyright (c) 2004-2011 Mik Firestone.  All rights reserved.  This program is
free software; you can redistibute it and/or modify it under the same terms as
Perl itself.

All references to TAM, Tivoli Access Manager, etc are copyrighted, trademarked
and otherwise patented by IBM.

=cut
1619