diff options
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | perl/Wallet/ACL.pm | 32 | ||||
-rwxr-xr-x | perl/t/server.t | 17 |
3 files changed, 45 insertions, 10 deletions
@@ -2,6 +2,12 @@ wallet 0.11 (unreleased) + When deleting an ACL on the server, verify that the ACL is not + referenced by any object first. Database referential integrity should + also catch this, but not all database backends may enforce referential + integrity. This also allows us to return a better error message + naming an object that's still using that ACL. + Fix portability to older Kerberos libraries without krb5_free_error_message. diff --git a/perl/Wallet/ACL.pm b/perl/Wallet/ACL.pm index 76e7354..44a82b2 100644 --- a/perl/Wallet/ACL.pm +++ b/perl/Wallet/ACL.pm @@ -21,7 +21,7 @@ use POSIX qw(strftime); # This version should be increased on any code change to this module. Always # use two digits for the minor version with a leading zero if necessary so # that it will sort properly. -$VERSION = '0.06'; +$VERSION = '0.07'; ############################################################################## # Constructors @@ -191,11 +191,25 @@ sub rename { # Destroy the ACL, deleting it out of the database. Returns true on success, # false on failure. +# +# Checks to ensure that the ACL is not referenced anywhere in the database, +# since we may not have referential integrity enforcement. It's not clear +# that this is the right place to do this; it's a bit of an abstraction +# violation, since it's a query against the object table. sub destroy { my ($self, $user, $host, $time) = @_; $time ||= time; eval { - my $sql = 'delete from acl_entries where ae_id = ?'; + my $sql = 'select ob_type, ob_name from objects where ob_owner = ? + or ob_acl_get = ? or ob_acl_store = ? or ob_acl_show = ? or + ob_acl_destroy = ? or ob_acl_flags = ?'; + my $sth = $self->{dbh}->prepare ($sql); + $sth->execute (($self->{id}) x 6); + my $entry = $sth->fetchrow_arrayref; + if (defined $entry) { + die "ACL in use by $entry->[0]:$entry->[1]"; + } + $sql = 'delete from acl_entries where ae_id = ?'; $self->{dbh}->do ($sql, undef, $self->{id}); $sql = 'delete from acls where ac_id = ?'; $self->{dbh}->do ($sql, undef, $self->{id}); @@ -525,13 +539,13 @@ array context and undef in scalar context. =item destroy(PRINCIPAL, HOSTNAME [, DATETIME]) -Destroys this ACL from the database. Note that this will fail due to -integrity constraint errors if the ACL is still referenced by any object; -the ACL must be removed from all objects first. Returns true on success -and false on failure. On failure, the caller should call error() to get -the error message. PRINCIPAL, HOSTNAME, and DATETIME are stored as -history information. PRINCIPAL should be the user who is destroying the -ACL. If DATETIME isn't given, the current time is used. +Destroys this ACL from the database. Note that this will fail if the ACL +is still referenced by any object; the ACL must be removed from all +objects first. Returns true on success and false on failure. On failure, +the caller should call error() to get the error message. PRINCIPAL, +HOSTNAME, and DATETIME are stored as history information. PRINCIPAL +should be the user who is destroying the ACL. If DATETIME isn't given, +the current time is used. =item error() diff --git a/perl/t/server.t b/perl/t/server.t index 7b30053..2a178e8 100755 --- a/perl/t/server.t +++ b/perl/t/server.t @@ -7,7 +7,7 @@ # # See LICENSE for licensing terms. -use Test::More tests => 341; +use Test::More tests => 349; use POSIX qw(strftime); use Wallet::Admin; @@ -923,6 +923,21 @@ is ($server->error, 'base:host/default.stanford.edu rejected: host' . ' default.stanford.edu not in .example.edu domain', ' with the right error'); +# Ensure that we can't destroy an ACL that's in use. +is ($server->acl_create ('test-destroy'), 1, 'Creating an ACL works'); +is ($server->create ('base', 'service/acl-user'), 1, 'Creating object works'); +is ($server->owner ('base', 'service/acl-user', 'test-destroy'), 1, + ' and setting owner'); +is ($server->acl_destroy ('test-destroy'), undef, + ' and now we cannot destroy that ACL'); +is ($server->error, + 'cannot destroy ACL 9: ACL in use by base:service/acl-user', + ' with the right error'); +is ($server->owner ('base', 'service/acl-user', ''), 1, + ' but after we clear the owner'); +is ($server->acl_destroy ('test-destroy'), 1, ' now we can destroy the ACL'); +is ($server->destroy ('base', 'service/acl-user'), 1, ' and the object'); + # Clean up. $setup->destroy; unlink 'wallet-db'; |