diff options
| author | Jon Robertson <jonrober@stanford.edu> | 2015-02-06 23:43:50 -0800 | 
|---|---|---|
| committer | Jon Robertson <jonrober@stanford.edu> | 2015-06-08 15:24:34 -0700 | 
| commit | 0e16def8a9e12f9b2232b29da79cdacb6710b086 (patch) | |
| tree | cbc454b69485aa2827200213f475d7ed5882b967 /perl | |
| parent | aebae838e3aa327e94d796bd99b48c169ffe6683 (diff) | |
Added acl replace command to wallet backend
New command for replacing the ownership of anything owned by a specific
ACL with another ACL.  This differs from acl rename in that it's to be
used when the destination ACL already exists and potentially already
owns some objects.
Change-Id: I765bebf499fe0f861abc2ffe1873990590beed36
Diffstat (limited to 'perl')
| -rw-r--r-- | perl/lib/Wallet/ACL.pm | 35 | ||||
| -rw-r--r-- | perl/lib/Wallet/Server.pm | 38 | ||||
| -rwxr-xr-x | perl/t/general/acl.t | 64 | 
3 files changed, 134 insertions, 3 deletions
| diff --git a/perl/lib/Wallet/ACL.pm b/perl/lib/Wallet/ACL.pm index a3b0146..370df8b 100644 --- a/perl/lib/Wallet/ACL.pm +++ b/perl/lib/Wallet/ACL.pm @@ -17,6 +17,7 @@ use strict;  use warnings;  use vars qw($VERSION); +use Wallet::Object::Base;  use DateTime;  use DBI; @@ -207,6 +208,32 @@ sub rename {      return 1;  } +# Moves everything owned by one ACL to instead be owned by another.  You'll +# normally want to use rename, but this exists for cases where the replacing +# ACL already exists and has things assigned to it.  Returns true on success, +# false on failure. +sub replace { +    my ($self, $replace_id, $user, $host, $time) = @_; +    $time ||= time; + +    my %search = (ob_owner => $self->{id}); +    my @objects = $self->{schema}->resultset('Object')->search (\%search); +    if (@objects) { +        for my $object (@objects) { +            my $type   = $object->ob_type; +            my $name   = $object->ob_name; +            my $object = eval { +                Wallet::Object::Base->new($type, $name, $self->{schema}); +            }; +            $object->owner ($replace_id, $user, $host, $time); +        } +    } else { +        $self->error ("no objects found for ACL $self->{id}"); +        return; +    } +    return 1; +} +  # Destroy the ACL, deleting it out of the database.  Returns true on success,  # false on failure.  # @@ -643,6 +670,14 @@ On failure, the caller should call error() to get the error message.  Note that rename() operations are not logged in the ACL history. +=item replace(ID) + +Replace this ACL with another.  This goes through each object owned by +the ACL and changes its ownership to the new ACL, leaving this acl owning +nothing (and probably then needing to be deleted).  Returns true on +success and false on failure.  On failure, the caller should call error() +to get the error message. +  =item show()  Returns a human-readable description of this ACL, including its diff --git a/perl/lib/Wallet/Server.pm b/perl/lib/Wallet/Server.pm index f6ea342..6af0570 100644 --- a/perl/lib/Wallet/Server.pm +++ b/perl/lib/Wallet/Server.pm @@ -734,6 +734,36 @@ sub acl_rename {      return 1;  } +# Move all ACLs owned by one ACL to another, or return undef and set the +# internal error. +sub acl_replace { +    my ($self, $old_id, $replace_id) = @_; +    unless ($self->{admin}->check ($self->{user})) { +        $self->acl_error ($old_id, 'replace'); +        return; +    } +    my $acl = eval { Wallet::ACL->new ($old_id, $self->{schema}) }; +    if ($@) { +        $self->error ($@); +        return; +    } +    if ($acl->name eq 'ADMIN') { +        $self->error ('cannot replace the ADMIN ACL'); +        return; +    } +    my $replace_acl = eval { Wallet::ACL->new ($replace_id, $self->{schema}) }; +    if ($@) { +        $self->error ($@); +        return; +    } + +    unless ($acl->replace ($replace_id, $self->{user}, $self->{host})) { +        $self->error ($acl->error); +        return; +    } +    return 1; +} +  # Destroy an ACL, deleting it out of the database.  Returns true on success.  # On failure, returns undef, setting the internal error.  sub acl_destroy { @@ -942,6 +972,14 @@ either the current name or the numeric ID.  NEW must not be all-numeric.  To rename an ACL, the current user must be authorized by the ADMIN ACL.  Returns true on success and false on failure. +=item acl_replace(OLD, NEW) + +Moves any object owned by the ACL identified by OLD to be instead owned by +NEW.  This goes through all objects owned by OLD and individually changes +the owner, along with history updates.  OLD and NEW may be either the name +or the numeric ID.  To replace an ACL, the current user must be authorized +by the ADMIN ACL.  Returns true on success and false on failure. +  =item acl_show(ID)  Returns a human-readable description, including membership, of the ACL diff --git a/perl/t/general/acl.t b/perl/t/general/acl.t index 1dd5c53..ff8ddad 100755 --- a/perl/t/general/acl.t +++ b/perl/t/general/acl.t @@ -12,11 +12,11 @@ use strict;  use warnings;  use POSIX qw(strftime); -use Test::More tests => 101; +use Test::More tests => 109;  use Wallet::ACL;  use Wallet::Admin; -use Wallet::Server; +use Wallet::Object::Base;  use lib 't/lib';  use Util; @@ -46,7 +46,7 @@ $acl = eval { Wallet::ACL->create (3, $schema, @trace) };  ok (!defined ($acl), 'Creating with a numeric name');  is ($@, "ACL name may not be all numbers\n", ' with the right error message');  $acl = eval { Wallet::ACL->create ('test', $schema, @trace) }; -ok (!defined ($acl), 'Creating a duplicate object'); +ok (!defined ($acl), 'Creating a duplicate acl');  like ($@, qr/^cannot create ACL test: /, ' with the right error message');  $acl = eval { Wallet::ACL->new ('test2', $schema) };  ok (!defined ($acl), 'Searching for a non-existent ACL'); @@ -231,6 +231,64 @@ is ($@, '', ' with no exceptions');  is ($acl->name, 'example', ' and the right name');  like ($acl->id, qr{\A[23]\z}, ' and an ID of 2 or 3'); +# Test replace. by creating three acls, then assigning two objects to the +# first, one to the second, and another to the third.  Then replace the first +# acl with the second, so that we can verify that multiple objects are moved, +# that an object already belonging to the new acl is okay, and that the +# objects with unrelated ACL are unaffected. +my ($acl_old, $acl_new, $acl_other, $obj_old_one, $obj_old_two, $obj_new, +    $obj_unrelated); +eval { +    $acl_old   = Wallet::ACL->create ('example-old', $schema, @trace); +    $acl_new   = Wallet::ACL->create ('example-new', $schema, @trace); +    $acl_other = Wallet::ACL->create ('example-other', $schema, @trace); +}; +is ($@, '', 'ACLs needed for testing replace are created'); +eval { +    $obj_old_one   = Wallet::Object::Base->create ('keytab', +                                                   'service/test1@EXAMPLE.COM', +                                                   $schema, @trace); +    $obj_old_two   = Wallet::Object::Base->create ('keytab', +                                                   'service/test2@EXAMPLE.COM', +                                                   $schema, @trace); +    $obj_new       = Wallet::Object::Base->create ('keytab', +                                                   'service/test3@EXAMPLE.COM', +                                                   $schema, @trace); +    $obj_unrelated = Wallet::Object::Base->create ('keytab', +                                                   'service/test4@EXAMPLE.COM', +                                                   $schema, @trace); +}; +is ($@, '', ' and so were needed objects'); +if ($obj_old_one->owner ('example-old', @trace) +    && $obj_old_two->owner ('example-old', @trace) +    && $obj_new->owner ('example-new', @trace) +    && $obj_unrelated->owner ('example-other', @trace)) { + +    ok (1, ' and setting initial ownership on the objects succeeds'); +} +is ($acl_old->replace('example-new', @trace), 1, +    ' and replace ran successfully'); +eval { +    $obj_old_one   = Wallet::Object::Base->new ('keytab', +                                                'service/test1@EXAMPLE.COM', +                                                $schema); +    $obj_old_two   = Wallet::Object::Base->new ('keytab', +                                                'service/test2@EXAMPLE.COM', +                                                $schema); +    $obj_new       = Wallet::Object::Base->new ('keytab', +                                                'service/test3@EXAMPLE.COM', +                                                $schema); +    $obj_unrelated = Wallet::Object::Base->new ('keytab', +                                                'service/test4@EXAMPLE.COM', +                                                $schema); +}; +is ($obj_old_one->owner, 'example-new', ' and first replace is correct'); +is ($obj_old_two->owner, 'example-new', ' and second replace is correct'); +is ($obj_new->owner, 'example-new', +    ' and object already with new acl is correct'); +is ($obj_unrelated->owner, 'example-other', +    ' and unrelated object ownership is correct'); +  # Clean up.  $setup->destroy;  END { | 
