File Coverage

File:/home/mik/work/module/Tivoli/AccessManager/Admin/ProtObject.pm
Coverage:99.4%

linestmtbrancondsubpodtimecode
1package Tivoli::AccessManager::Admin::ProtObject;
2
15
15
15
131
53
128
use strict;
3
15
15
15
187
63
133
use warnings;
4
15
15
15
181
56
195
use Carp;
5
15
15
15
220
62
245
use Data::Dumper;
6
7
15
15
15
198
59
151
use Tivoli::AccessManager::Admin::Response;
8
9#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
10# $Id: ProtObject.pm 327 2006-11-20 18:59:26Z mik $
11#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
12$Tivoli::AccessManager::Admin::ProtObject::VERSION = '0.04';
13
15
148
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::ProtObject',
19
15
15
185
52
            );
20
21sub new {
22
24
1
191
    my $class = shift;
23
24
142
    my $cont = shift;
24
24
115
    my $type = 0;
25
26
24
595
    unless ( defined($cont) and UNIVERSAL::isa($cont,'Tivoli::AccessManager::Admin::Context' ) ) {
27
2
49
        warn "Incorrect syntax -- did you forget the context?\n";
28
2
31
        return undef;
29    }
30
31
22
175
    if ( @_ % 2 ) {
32
2
40
        warn "Invalid syntax -- you did not send a hash\n";
33
2
27
        return undef;
34    }
35
20
203
    my %opts = @_;
36
20
233
    my $resp = Tivoli::AccessManager::Admin::Response->new;
37
38
20
194
    my $self = bless {}, $class;
39
40
20
227
    $self->{name} = $opts{name} || '';
41
20
264
    $self->{description} = $opts{description} || '';
42
20
125
    $self->{context} = $cont;
43
20
183
    $type = $opts{type} || 0;
44
45    #Figure out the object type, or set to unknown.
46
20
482
    unless (($type =~ /^\d+$/) and ($type < 18)) {
47
2
24
        carp("Unknown object type: $type");
48
2
22
        return undef;
49    }
50
51
18
121
    $self->{type} = $type;
52
18
337
    $self->_protstash;
53
18
846023
    if ( $self->protobj_exists($resp) ) {
54
9
164
        $self->{exist} = 1;
55
9
216
        $self->get;
56    }
57
58
18
194
    return $self;
59}
60
61sub create {
62
16
1
106
    my $self = shift;
63
16
174
    my $resp = Tivoli::AccessManager::Admin::Response->new;
64
65
16
120
    unless ( ref $self ) {
66
6
35
        my $pd = shift;
67
6
105
        unless (defined($pd) and UNIVERSAL::isa($pd,'Tivoli::AccessManager::Admin::Context')){
68
2
20
            $resp->set_message("Invalid Tivoli::AccessManager::Admin::Context object");
69
2
18
            $resp->set_isok(0);
70
2
19
            return $resp;
71        }
72
4
34
        $self = $self->new( $pd, @_ );
73
4
109
        unless ( defined $self ) {
74
1
17
            $resp->set_isok(0);
75
1
9
            $resp->set_message('Error creating object');
76
1
9
            return $resp;
77        }
78    }
79
80
13
106
    if ( @_ % 2 ) {
81
1
6
        $resp->set_message("Invalid syntax -- send a hash");
82
1
6
        $resp->set_isok(0);
83
1
5
        return $resp;
84    }
85
12
112
    my %opts = @_;
86
12
171
    my $type = $opts{type} || $self->{type} || 0;
87
88
12
91
    unless ( $self->{name} ) {
89
3
66
        $self->{name} = $opts{name} || '';
90    }
91
92
12
76
    unless ( $self->{name} ) {
93
1
18
        $resp->set_message("Cannot create a protected object with no name");
94
1
18
        $resp->set_isok(0);
95
1
12
        return $resp;
96    }
97
98
11
105
    if ( $self->exist ) {
99
2
14
        $resp->set_message("Protected object already exists");
100
2
14
        $resp->set_iswarning(1);
101
2
12
        $resp->set_value($self);
102
2
14
        return $resp;
103    }
104
105
9
222
    unless ( $type =~ /^\d+$/ and $type < 18 ) {
106
2
33
        $resp->set_message("Unknown object type: $type");
107
2
20
        $resp->set_isok(0);
108
2
27
        return $resp;
109    }
110
7
44
    $self->{type} = $type;
111
112
7
321609
    my $rc = $self->protobj_create( $resp, $self->{type},
113                                    $opts{description} || '' );
114
7
213
    if ( $resp->isok ) {
115
6
77
        $resp->set_value($self);
116
6
57
        $self->{exist} = 1;
117
6
57
        $self->get;
118    }
119
120
7
247
    return $resp;
121}
122
123sub delete {
124
8
1
57
    my $self = shift;
125
8
113
    my $resp = Tivoli::AccessManager::Admin::Response->new;
126
127
8
92
    unless ( $self->{exist} ) {
128
1
12
        $resp->set_message("Cannot delete an object that doesn't exist");
129
1
12
        $resp->set_isok(0);
130
1
16
        return $resp;
131    }
132
133
7
327794
    my $rc = $self->protobj_delete($resp);
134
7
208
    if ( $resp->isok ) {
135
6
82
        $self->{exist} = 0;
136    }
137
7
92
    return $resp;
138}
139
140sub get {
141
33
1
224
    my $self = shift;
142
33
451
    my $resp = Tivoli::AccessManager::Admin::Response->new;
143
144
33
1615329
    my @rc = $self->protobj_get($resp);
145    # I really have no clue what this will return. I am going to leave this
146    # here as a stub, and figure everything out later. Watch this space for
147    # something new.
148
33
982
    $resp->isok && $resp->set_value(\@rc);
149
33
392
    return $resp;
150}
151
152sub acl {
153
6
1
29
    my $self = shift;
154
6
43
    my %opts = @_;
155
6
55
    my $resp = Tivoli::AccessManager::Admin::Response->new;
156
6
19
    my %ret;
157
158
6
37
    if ( defined $opts{detach} ) {
159
2
92063
        my $rc = $self->protobj_detachacl( $resp );
160
2
35
        return $resp unless $resp->isok;
161
1
9
        $self->get;
162    }
163
164
5
38
    if ( defined $opts{attach} ) {
165
3
136767
        my $rc = $self->protobj_attachacl( $resp, $opts{attach} );
166
3
68
        return $resp unless $resp->isok;
167
2
20
        $self->get;
168    }
169
170
4
142
    $ret{attached} = $self->protobj_getaclid() || '';
171
4
62
    $ret{effective} = $self->protobj_geteffaclid();
172
173
4
34
    $resp->set_value( \%ret );
174
4
39
    return $resp;
175}
176
177sub authzrule {
178
11
1
66
    my $self = shift;
179
11
110
    my %opts = @_;
180
11
138
    my $resp = Tivoli::AccessManager::Admin::Response->new;
181
11
59
    my %ret;
182
183
11
80
    if ( defined $opts{detach} ) {
184
5
222222
        my $rc = $self->protobj_detachauthzrule( $resp );
185
5
147
        return $resp unless $resp->isok;
186
3
48
        $self->get;
187    }
188
189
9
131
    if ( defined $opts{attach} ) {
190
5
236701
        my $rc = $self->protobj_attachauthzrule( $resp, $opts{attach} );
191
5
212
        return $resp unless $resp->isok;
192
3
43
        $self->get;
193    }
194
195
7
328
    $ret{attached} = $self->protobj_getauthzruleid() || '';
196
7
183
    $ret{effective} = $self->protobj_geteffauthzruleid() || '';
197
198
7
72
    $resp->set_value( \%ret );
199
7
103
    return $resp;
200}
201
202sub pop {
203
1
1
9
    my $self = shift;
204
1
19
    my $resp = Tivoli::AccessManager::Admin::Response->new;
205
1
7
    my %ret;
206
207
1
67
    $ret{attached} = $self->protobj_getpopid();
208
1
44
    $ret{effective} = $self->protobj_geteffpopid();
209
210
1
11
    $resp->set_value( \%ret );
211
1
9
    return $resp;
212}
213
214sub type {
215
9
1
79
    my $self = shift;
216
9
131
    my $resp = Tivoli::AccessManager::Admin::Response->new;
217
9
42
    my $type;
218
219
9
105
    if ( @_ == 1 ) {
220
3
25
        $type = shift;
221    }
222    elsif ( @_ % 2 ) {
223
1
15
        $resp->set_message("Invalid syntax");
224
1
10
        $resp->set_isok(0);
225
1
10
        return $resp;
226    }
227    elsif ( @_ ) {
228
3
28
        my %opts = @_;
229
3
55
        $type = $opts{type} || 0;
230    }
231
232
8
69
    unless ( $self->{exist} ) {
233
1
13
        $resp->set_message("Cannot get/set the type of a non-existent object");
234
1
11
        $resp->set_isok(0);
235
1
10
        return $resp;
236    }
237
238
7
45
    if ($type) {
239
4
110
        unless ( $type =~ /^\d+$/ and $type < 18 ) {
240
2
29
            $resp->set_message("Invalid object type $type");
241
2
20
            $resp->set_isok(0);
242
2
18
            return $resp;
243        }
244
2
96157
        my $rc = $self->protobj_settype( $resp, $type );
245
2
54
        if ( $resp->isok ) {
246
1
48007
            $self->protobj_get($resp);
247        }
248    }
249
250
5
58
    $resp->isok && $resp->set_value( $self->protobj_gettype );
251
5
45
    return $resp;
252}
253
254sub description {
255
7
1
54
    my $self = shift;
256
7
104
    my $resp = Tivoli::AccessManager::Admin::Response->new;
257
7
28
    my $desc;
258
259
7
81
    if ( @_ == 1 ) {
260
2
12
        $desc = shift;
261    }
262    elsif ( @_ % 2 ) {
263
1
12
        $resp->set_message("Invalid syntax");
264
1
14
        $resp->set_isok(0);
265
1
9
        return $resp;
266    }
267    elsif ( @_ ) {
268
2
20
        my %opts = @_;
269
2
36
        $desc = $opts{description} || 0;
270    }
271
272
273
6
49
    unless ( $self->{exist} ) {
274
1
12
        $resp->set_message("Cannot describe a non-existent object");
275
1
9
        $resp->set_isok(0);
276
1
5
        return $resp;
277    }
278
279
5
27
    if ( $desc ) {
280
2
94727
        my $rc = $self->protobj_setdesc($resp,$desc);
281
2
57
        if ( $resp->isok ) {
282
1
49904
            $self->protobj_get($resp);
283        }
284    }
285
286
5
64
    $resp->isok && $resp->set_value( $self->protobj_getdesc );
287
5
50
    return $resp;
288}
289
290sub policy_attachable {
291
7
1
45
    my $self = shift;
292
7
80
    my $resp = Tivoli::AccessManager::Admin::Response->new;
293
7
31
    my $att = undef;
294
295
7
106
    if ( @_ == 1 ) {
296
2
10
        $att = shift;
297    }
298    elsif ( @_ % 2 ) {
299
1
9
        $resp->set_message("Invalid syntax");
300
1
10
        $resp->set_isok(0);
301
1
8
        return $resp;
302    }
303    elsif ( @_ ) {
304
2
20
        my %opts = @_;
305
2
38
        $att = $opts{att} || 0;
306    }
307
308
6
43
    if ( defined($att) ) {
309
4
144773
        my $rc = $self->protobj_setpolicyattachable($resp,$att);
310
4
93
        if ( $resp->isok ) {
311
3
149608
            $self->protobj_get($resp);
312        }
313    }
314
315
6
116
    $resp->isok && $resp->set_value( $self->protobj_getpolicyattachable );
316
6
56
    return $resp;
317}
318
319sub list {
320
1
1
8
    my $self = shift;
321
1
16
    my $resp = Tivoli::AccessManager::Admin::Response->new;
322
1
8
    my @rc;
323
324
1
47032
    @rc = $self->protobj_list( $resp );
325
326
1
31
    $resp->isok && $resp->set_value( \@rc );
327
1
12
    return $resp;
328}
329
330sub find {
331
9
1
64
    my $class = shift;
332
9
117
    my $resp = Tivoli::AccessManager::Admin::Response->new;
333
334
9
47
    my ($pd,@rc);
335
336
9
72
    if ( ref($class) ) {
337
2
15
        $pd = $class->{context};
338    }
339    else {
340
7
28
        $pd = shift;
341    }
342
343
9
207
    unless (defined($pd) and UNIVERSAL::isa($pd,'Tivoli::AccessManager::Admin::Context')){
344
2
20
        $resp->set_message("Invalid Tivoli::AccessManager::Admin::Context object");
345
2
22
        $resp->set_isok(0);
346
2
13
        return $resp;
347    }
348
7
88
    if ( @_ % 2 ) {
349
1
10
        $resp->set_message("Invalid syntax");
350
1
10
        $resp->set_isok(0);
351
1
8
        return $resp;
352    }
353
6
62
    my %opts = @_;
354
6
64
    if ( defined $opts{acl} ) {
355
2
95109
        @rc = protobj_listbyacl( $pd, $resp, $opts{acl} );
356    }
357    elsif ( defined $opts{authzrule} ) {
358
3
143716
        @rc = protobj_listbyauthzrule( $pd, $resp, $opts{authzrule} );
359    }
360    else {
361
1
10
        $resp->set_message("Must find by authzrule or acl");
362
1
14
        $resp->set_isok(0);
363    }
364
365
6
178
    $resp->isok && $resp->set_value( \@rc );
366
6
118
    return $resp;
367}
368
369sub _remvalue {
370
5
41
    my $self = shift;
371
5
20
    my $dead = shift;
372
373
5
61
    my $resp = Tivoli::AccessManager::Admin::Response->new;
374
375
5
5
32
61
    for my $key ( keys %{$dead} ) {
376
5
44
        if ( ref( $dead->{$key} ) ) {
377
2
2
16
27
            for my $val ( @{$dead->{$key}} ) {
378
2
95154
                my $rc = $self->protobj_attrdelval( $resp, $key, $val );
379
2
63
                return $resp unless $resp->isok;
380            }
381        }
382        else {
383
3
145072
            my $rc = $self->protobj_attrdelval( $resp, $key, $dead->{$key} );
384
3
92
            return $resp unless $resp->isok;
385        }
386    }
387
2
31
    return $resp;
388}
389
390sub _remkey {
391
5
33
    my $self = shift;
392
5
22
    my $dead = shift;
393
394
5
48
    my $resp = Tivoli::AccessManager::Admin::Response->new;
395
396
5
52
    if ( ref( $dead ) ) {
397
4
4
15
24
        for my $key ( @{$dead} ) {
398
6
290522
            my $rc = $self->protobj_attrdelkey( $resp, $key );
399
6
186
            return $resp unless $resp->isok;
400        }
401    }
402    else {
403
1
45964
        my $rc = $self->protobj_attrdelkey( $resp, $dead );
404    }
405
406
3
46
    return $resp;
407}
408
409sub _addval {
410
7
38
    my $self = shift;
411
7
31
    my $add = shift;
412
413
7
63
    my $resp = Tivoli::AccessManager::Admin::Response->new;
414
415
7
7
37
65
    for my $key ( keys %{$add} ) {
416
11
93
        if ( ref( $add->{$key} ) ) {
417
5
5
22
35
            for my $val ( @{$add->{$key}} ) {
418
6
284743
                my $rc = $self->protobj_attrput( $resp, $key, $val );
419
6
182
                return $resp unless $resp->isok;
420            }
421        }
422        else {
423
6
290769
            my $rc = $self->protobj_attrput( $resp, $key, $add->{$key} );
424
6
195
            return $resp unless $resp->isok;
425        }
426    }
427
428
4
62
    return $resp
429}
430
431sub attributes {
432
19
1
164
    my $self = shift;
433
19
276
    my $resp = Tivoli::AccessManager::Admin::Response->new;
434
19
117
    my $rhash = {};
435
19
342
    my %dispatch = ( remove => \&_remvalue,
436                     removekey => \&_remkey,
437                     add => \&_addval
438                    );
439
440
19
172
    if ( @_ % 2 ) {
441
1
10
        $resp->set_message("Invalid syntax");
442
1
11
        $resp->set_isok(0);
443
1
10
        return $resp;
444    }
445
18
121
    my %opts = @_;
446
447
18
110
    for my $action ( qw/remove removekey add/ ) {
448
45
358
        if ( defined $opts{$action} ) {
449
17
142
            $resp = $dispatch{$action}->($self,$opts{$action});
450
17
210
            return $resp unless $resp->isok;
451        }
452    }
453
454    # just in case one of the above branches was actually taken, refresh the
455    # cached object
456
9
103
    $self->get($resp);
457
9
684
    for my $key ( $self->protobj_attrlist ) {
458
17
866
        $rhash->{$key} = [ $self->protobj_attrget($key) ];
459    }
460
461
9
115
    $resp->isok && $resp->set_value( $rhash );
462
9
177
    return $resp;
463}
464
465sub DESTROY {
466
20
165
    my $self = shift;
467
20
357
    $self->_protobj_free();
468}
469
470
471
5
1
188526
sub name { $_[0]->protobj_getid }
472
13
1
123
sub exist { $_[0]->{exist} }
473
4741;
475
476 - 927
=head1 NAME

Tivoli::AccessManager::Admin::ProtObject

=head1 SYNOPSIS

  use Tivoli::AccessManager::Admin;

  my $resp;
  my $pd = Tivoli::AccessManager::Admin->new( password => 'foobar' );
  my $pobj = Tivoli::AccessManager::Admin::ProtObject->new( $pdadmin, 
					  name => '/test/monkey');

  # Create the object unless it already exists
  $resp = $pobj->create unless $pobj->exist;

  # Set the type and the description
  $resp = $pobj->type( 'container' );
  $resp = $pobj->description( 'Monkey!' );

  # Attach an ACL
  $resp = $pobj->acl( attach => 'default-webseal' );

  # Detach  an ACL
  $resp = $pobj->acl( detach => 1 );

  # Get the attached and effective ACL
  $resp = $pobj->acl;
  my $href = $resp->value;
  print "Effective ACL: $href->{effective}\n";
  print "Attached ACL: $href->{attached}\n";

  # Find out where else the ACL is attached
  $resp = Tivoli::AccessManager::Admin::ProtObject->find( acl => $href->{attached} );

  # Attach an authorization rule
  $resp = $pobj->authzrule( attach => 'silly' );

  # Find out where else the authzrule is attached
  $resp = Tivoli::AccessManager::Admin::ProtObject->find( authzrule => 'silly' );

  # Detach an authzrule
  $resp = $pobj->authzrule( detach => 1 );

  # Get the attached and effective Authzrule
  $resp = $pobj->authzrule;
  my $href = $resp->value;
  print "Effective Authz: $href->{effective}\n";
  print "Attached Authz: $href->{attached}\n";

  # Get a list of the objects under /test
  my $top = Tivoli::AccessManager::Admin::ProtObject->new( $pd, name => '/test' );
  $resp = $top->list;

  # See what POPs are attached to the object
  $resp = $pobj->pop;

  # Set is_policy_attachable bit to 0
  $resp = $pobj->policy_attachable( 0 );
 
  # Add some attributes
  $resp = $pobj->attributes( add => { evil => 1, 
				      smoking => [ qw/strawberry crack/ ]
				    });
  # Remove one of the values
  $resp = $pobj->attributes( remove => { smoking => 'crack' } );

  # Remove the keys
  $resp = $pobj->attributes( removekey => [ qw/evil smoking/ ] )

  # Finally, delete it
  $resp = $pobj->delete;

=head1 DESCRIPTION

B<Tivoli::AccessManager::Admin::ProtObject> provides the interface to the protected object API
calls.

=head1 CONSTRUCTORS

=head2 new( PDADMIN[, name =E<gt> NAME, type =E<gt> TYPE, description => DESC ])

Creates a new L<Tivoli::AccessManager::Admin::ProtObject> object.

=head3 Parameters

=over 4

=item PDADMIN

A blessed and initialized L<Tivoli::AccessManager::Admin::Context>.  This is the only required
parameter.

=item name =E<gt> NAME

The name of the protected object.  This usually looks an awful lot like a UNIX
path.

=item type =E<gt> TYPE

The protected object type.  See L</"Types"> for a full discussion of the
allowed values.

=item description =E<gt> DESC

Some descriptive text.

=back

=head3 Returns

A blessed L<Tivoli::AccessManager::Admin::ProtObject> object.  If the type is specified and it
is not a valid type, you will get a nasty warning and a return of undef.

=head2 create(PDADMIN,name =E<gt> NAME[, type =E<gt> TYPE, description => DESC ])

L</"create">, as with all the other modules, can be used to both initialize the
L<Tivoli::AccessManager::Admin::ProtObject> instance and create the object in the policy
database.

In this case, the newly created instance will be returned to you in a
L<Tivoli::AccessManager::Admin::Response> object.  See that module's Fine Documentation to learn
how to get it.

=head3 Parameters

The parameters are identical to those for L</"new">.  The only difference is
that the name is now a required parameter.

=head3 Returns

A L<Tivoli::AccessManager::Admin::Response> object containing the new instance.

=head1 CLASS METHODS

=head2 find(PDADMIN, E<lt>acl =E<gt> 'acl name' | authzrule =E<gt> 'auth rule name'E<gt>)

Searches the object space for every object to which either the ACL or the
authzrule is attached.  You can use this method, but I think the find methods
for L<Tivoli::AccessManager::Admin::ACL> and L<Tivoli::AccessManager::Admin::Authzrule> make more sense.

=head3 Parameters

You only need to provide either the acl or authzrule.  If both are provided,
the ACL will win.

=over 4

=item PDADMIN

A blessed and initialized L<Tivoli::AccessManager::Admin::Context>.  This is the only required
parameter.

=item acl =E<gt> 'acl name'

The name of the ACL for which we are searching.  

=item authzrule =E<gt> 'auth rule name'

The name of the authzrule for which we are searching.  

=back

=head3 Returns

A L<Tivoli::AccessManager::Admin::Response> object containing a possibly empty array of all
objects found.


=head1 METHODS

Unless otherwise mentioned, everything returns a L<Tivoli::AccessManager::Admin::Response>
object.

=head2 create([ name =E<gt> NAME, type =E<gt> TYPE, description => DESC ])

Yes, L</"create"> can also be used as a method.

=head3 Parameters

The same as L</"create"> the constructor.  You must provide the name of you
did not provide it to L</"new">.

=head3 Returns

A L<Tivoli::AccessManager::Admin::Response> object containing the new instance.

=head2 delete

Deletes the object from the policy database.

=head3 Parameters

None

=head3 Returns

Success if the object exists and it can be deleted.  

=head2 get

Refreshes the cached ivadmin_protobj structure.  This should almost never need
to be used by you, unless you decide to bypass my nice interface and go
directly to the API calls.

=head3 Parameters

None

=head3 Returns

None

=head2 acl([attach => 'ACL Name', detach => 'ACL Name'])

Attaches or detaches an ACL from the object.  If called with no parameters,
returns the attached and effective ACL for that object.  If called with both
attach and detach, detaches are handled first.

=head3 Parameters

=over 4

=item attach =E<gt> 'ACL Name'

This will cause the named ACL to be attached to the the object.  

=item detach =E<gt> 'ACL Name'

The will cause the named ACL to be detached.

=back

=head3 Returns

Any attempt to attach an ACL that does not exist or detach an ACL not already
attached will result in an error.

Otherwise, you will get a hash that looks like this:

=over 4

=item attached 

The name of the attached ACL if any

=item effective

The name of the effective ACL.

=back

=head2 authzrule([attach =E<gt>  "Authzrule", detach =E<gt> "Authzrule"])

Attaches and detaches authorization rules.  Unlike L</"acl">, this code is
currently completely untested.  I don't yet know how to create authzrules to
test it.

=head3 Parameters

=over 4

=item attach =E<gt> 'authzrule Name'

This will cause the named authzrule to be attached to the the object.  

=item detach =E<gt> 'authzrule Name'

The will cause the named authzrule to be detached.

=back

=head3 Returns

Any attempt to attach an authzrule that does not exist or detach an authzrule
not already attached will result in an error.

Otherwise, you will get a hash that looks like this:

=over 4

=item attached 

The name of the attached authzrule if any

=item effective

The name of the effective authzrule.

=back

=head2 pop

Returns the attached and effective POP.  See L<Tivoli::AccessManager::Admin::POP> for the attach
and detach methods.  Don't look at me -- I didn't write the API.

=head3 Parameters

None

=head3 Returns

A hash that looks like this:

=over 4

=item attached 

The name of the attached POP if any

=item effective

The name of the effective POP.

=back

=head2 type([TYPE])

Sets or gets the object's type.  See L</"Types"> for a discussion of the valid types.

=head3 Parameters

=over 4

=item type =E<gt> TYPE

The object's new type.  

=back

=head3 Returns

The object's type.

=head2 description(['DESC'])

Give the object some enlightening description.

=head3 Parameters

=over 4

=item 'DESC'

The new description.  This is optional, as usual.

=back

=head3 Returns

The object's description.

=head2 policy_attachable([0|1])

Allow policies to be attached or not.

=head3 Parameters

=over 4

=item  0 | 1

0 to disable attaching policies, 1 to enable.

=back

=head3 Returns

1 if the object allows policies to be attached, 0 otherwise.

=head2 list

Lists all of the object immediately below the object in question.

=head3 Parameters

None

=head3 Returns

A list, possibly empty, of all the sub-objects.

=head2 attributes([add =E<gt> { key => [qw/value0 value1/] | 'value0' }, remove =E<gt> { key => [qw/value0 value1/] | 'value0' }, removekey =E<gt> [qw/key0 key1] ] )

Adds key/value attributes to an object, removes the values and removes the
entire key/value pairs.  I find these to be the more ... annoying functions.

=head3 Parameters

=over 4

=item add =E<gt> { key =E<gt> [qw/ value0 value1/] | 'value0' }

Causes L</"attribute"> to add any number of key/value pairs to the object.  As
you can have multiple values associated with any given key, you can either use
an array reference for multiple values, or a simple scalar if you are playing
with only one.

You can, obviously, add multiple keys with the same call.  You can also,
strangely enough, add the same value to a key multiple times.

=item remove =E<gt> { key =E<gt> [qw/ value0 value1/] | 'value0' }

Removes the specified value(s) from the key.  This does not remove the key,
simply the values from the key.  You will get an error if you try to remove a
value that is not defined.

=item removekey =E<gt> [qw/key0 key1]

Removes both the attribute and any associated values from the object.

=back

=head3 Returns

A hash of lists.  The hash is keyed off of the attribute names.  The values
for each attribute are returned as a list -- even if there is only one value.  

=head2 name

Returns the name of the object.  This is returned as a simple string B<not> in
a L<Tivoli::AccessManager::Admin::Response> object.

=head2 exist

Returns a boolean indicating if the object exists or not.  This does B<not>
return a L<Tivoli::AccessManager::Admin::Response> object.

=head1 ACKNOWLEDGEMENTS

See L<Tivoli::AccessManager::Admin> for the full list of acknoledgements.

=head1 BUGS

None known yet, although I am thinking there are parts of the interface that
need to change.  I do not like having to use a hash in the methods that
require only one parameter, but I do not like breaking the pattern almost as
much.

=head1 AUTHOR

Mik Firestone <mikfire@gmail.com>

=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.

Standard IBM copyright, trademark, patent and ownership statement.

=cut
928