From 863dfd901b4bba011b4dea27648fed85dd06d297 Mon Sep 17 00:00:00 2001 From: John Doe Date: Mon, 17 Feb 2020 20:07:15 -0800 Subject: [PATCH] acl comment and build changes revert version number --- perl/lib/Wallet/ACL.pm | 81 ++++++- perl/lib/Wallet/Admin.pm | 20 +- perl/lib/Wallet/Object/Base.pm | 12 +- perl/lib/Wallet/Report.pm | 7 +- perl/lib/Wallet/Schema.pm | 3 +- perl/lib/Wallet/Schema/Result/Acl.pm | 8 + perl/lib/Wallet/Server.pm | 26 ++ perl/sql/Wallet-Schema-0.10-0.11-MySQL.sql | 9 + .../Wallet-Schema-0.10-0.11-PostgreSQL.sql | 8 + perl/sql/Wallet-Schema-0.10-0.11-SQLite.sql | 7 + perl/sql/Wallet-Schema-0.11-MySQL.sql | 216 +++++++++++++++++ perl/sql/Wallet-Schema-0.11-PostgreSQL.sql | 223 +++++++++++++++++ perl/sql/Wallet-Schema-0.11-SQLite.sql | 226 ++++++++++++++++++ perl/t/general/acl.t | 64 ++++- perl/t/general/admin.t | 12 +- perl/t/general/init.t | 5 +- perl/t/general/report.t | 5 +- perl/t/general/server.t | 47 ++-- perl/t/lib/Util.pm | 57 +++-- perl/t/object/base.t | 2 +- perl/t/object/file.t | 2 +- perl/t/object/keytab.t | 2 +- perl/t/object/password.t | 2 +- perl/t/verifier/nested.t | 4 +- server/wallet-backend.in | 27 ++- 25 files changed, 994 insertions(+), 81 deletions(-) create mode 100644 perl/sql/Wallet-Schema-0.10-0.11-MySQL.sql create mode 100644 perl/sql/Wallet-Schema-0.10-0.11-PostgreSQL.sql create mode 100644 perl/sql/Wallet-Schema-0.10-0.11-SQLite.sql create mode 100644 perl/sql/Wallet-Schema-0.11-MySQL.sql create mode 100644 perl/sql/Wallet-Schema-0.11-PostgreSQL.sql create mode 100644 perl/sql/Wallet-Schema-0.11-SQLite.sql diff --git a/perl/lib/Wallet/ACL.pm b/perl/lib/Wallet/ACL.pm index 948b71c6..686c2159 100644 --- a/perl/lib/Wallet/ACL.pm +++ b/perl/lib/Wallet/ACL.pm @@ -22,6 +22,8 @@ use Wallet::Object::Base; our $VERSION = '1.04'; +my $TZ = DateTime::TimeZone->new( name => 'local' ); + ############################################################################## # Constructors ############################################################################## @@ -50,6 +52,7 @@ sub new { schema => $schema, id => $data->ac_id, name => $data->ac_name, + comment => $data->ac_comment, }; bless ($self, $class); return $self; @@ -75,7 +78,7 @@ sub create { die "unable to retrieve new ACL ID" unless defined $id; # Add to the history table. - my $date = DateTime->from_epoch (epoch => $time); + my $date = DateTime->from_epoch (epoch => $time, time_zone => $TZ); %record = (ah_acl => $id, ah_name => $name, ah_action => 'create', @@ -126,6 +129,12 @@ sub name { return $self->{name}; } +# Returns the comment of the ACL. +sub comment { + my ($self)= @_; + return $self->{comment}; +} + # Given an ACL scheme, return the mapping to a class by querying the # database, or undef if no mapping exists. Also load the relevant module. sub scheme_mapping { @@ -161,7 +170,7 @@ sub log_acl { unless ($action =~ /^(add|remove|rename)\z/) { die "invalid history action $action"; } - my $date = DateTime->from_epoch (epoch => $time); + my $date = DateTime->from_epoch (epoch => $time, time_zone => $TZ); my %record = (ah_acl => $self->{id}, ah_name => $self->{name}, ah_action => $action, @@ -294,7 +303,7 @@ sub destroy { $entry->delete if defined $entry; # Create new history line for the deletion. - my $date = DateTime->from_epoch (epoch => $time); + my $date = DateTime->from_epoch (epoch => $time, time_zone => $TZ); my %record = (ah_acl => $self->{id}, ah_name => $self->{name}, ah_action => 'destroy', @@ -355,6 +364,49 @@ sub add { return 1; } +# Get the comment of an ACL. +sub get_comment { + my ($self) = @_; + return $self->comment(); +} + +# Set the comment of an ACL. +sub set_comment { + my ($self, $comment) = @_; + + if (defined($comment)) { + if ($comment eq q{}) { + $comment = undef; + } else { + if (length($comment) > 255) { + $self->error ('comment cannot be longer than 255 characters'); + return; + } + } + eval { + my $guard = $self->{schema}->txn_scope_guard; + my %search = (ac_id => $self->{id}); + my $acl = $self->{schema}->resultset('Acl')->find (\%search); + $acl->ac_comment($comment); + $acl->update; + $guard->commit; + + # Re-read (comment field may have been truncated) + $acl = $self->{schema}->resultset('Acl')->find (\%search); + $self->{comment} = $acl->ac_comment; + }; + if ($@) { + $self->error ("cannot update comment for ACL $self->{name}: $@"); + return; + } + } else { + $self->error ("missing comment in set_comment for ACL $self->{name}"); + return; + } + + return 1; +} + # Remove an ACL entry to this ACL. Returns true on success and false on # failure. Detect the case where no such row exists before doing the delete # so that we can provide a good error message. @@ -396,6 +448,7 @@ sub list { eval { my $guard = $self->{schema}->txn_scope_guard; my %search = (ae_id => $self->{id}); + my %options = (order_by => { -asc => [qw/ah_on ah_id/] }); my @entry_recs = $self->{schema}->resultset('AclEntry') ->search (\%search); for my $entry (@entry_recs) { @@ -426,8 +479,18 @@ sub show { my $output = "Members of ACL $name (id: $id) are:\n"; for my $entry (sort { $$a[0] cmp $$b[0] or $$a[1] cmp $$b[1] } @entries) { my ($scheme, $identifier) = @$entry; - $output .= " $scheme $identifier\n"; + if ($identifier) { + $output .= " $scheme $identifier\n"; + } else { + $output .= " $scheme\n"; + } } + + my $comment = $self->comment; + if ($comment) { + $output .= "comment: $comment\n"; + } + return $output; } @@ -438,7 +501,7 @@ sub history { eval { my $guard = $self->{schema}->txn_scope_guard; my %search = (ah_acl => $self->{id}); - my %options = (order_by => 'ah_on'); + my %options = (order_by => { -asc => [qw/ah_on ah_id/] }); my @data = $self->{schema}->resultset('AclHistory') ->search (\%search, \%options); for my $data (@data) { @@ -446,8 +509,12 @@ sub history { $date->set_time_zone ('local'); $output .= sprintf ("%s %s ", $date->ymd, $date->hms); if ($data->ah_action eq 'add' || $data->ah_action eq 'remove') { - $output .= sprintf ("%s %s %s", $data->ah_action, - $data->ah_scheme, $data->ah_identifier); + if ($data->ah_identifier) { + $output .= sprintf ("%s %s %s", $data->ah_action, + $data->ah_scheme, $data->ah_identifier); + } else { + $output .= sprintf ("%s %s", $data->ah_action, $data->ah_scheme); + } } elsif ($data->ah_action eq 'rename') { $output .= 'rename from ' . $data->ah_name; } else { diff --git a/perl/lib/Wallet/Admin.pm b/perl/lib/Wallet/Admin.pm index 707f4105..bc6c57bf 100644 --- a/perl/lib/Wallet/Admin.pm +++ b/perl/lib/Wallet/Admin.pm @@ -85,6 +85,13 @@ sub DESTROY { sub initialize { my ($self, $user) = @_; + # Suppress warnings that actually are just informational messages. + local $SIG{__WARN__} = sub { + my ($warn) = @_; + return if $warn =~ m{NOTICE: table "\S+" does not exist, skipping}; + warn $warn; + }; + # Deploy the database schema from DDL files, if they exist. If not then # we automatically get the database from the Schema modules. $self->{schema}->deploy ({}, $Wallet::Config::DB_DDL_DIRECTORY); @@ -154,6 +161,14 @@ sub default_data { # false on failure. sub reinitialize { my ($self, $user) = @_; + + # Suppress warnings that actually are just informational messages. + local $SIG{__WARN__} = sub { + my ($warn) = @_; + return if $warn =~ m{NOTICE: table "\S+" does not exist, skipping}; + warn $warn; + }; + return unless $self->destroy; return $self->initialize ($user); } @@ -165,9 +180,9 @@ sub destroy { # Get an actual DBI handle and use it to delete all tables. my $dbh = $self->dbh; - my @tables = qw/acl_entries object_history objects acls acl_history + my @tables = qw/acl_entries duo object_history objects acls acl_history acl_schemes enctypes flags keytab_enctypes keytab_sync sync_targets - duo types dbix_class_schema_versions/; + types dbix_class_schema_versions/; for my $table (@tables) { my $sql = "DROP TABLE IF EXISTS $table"; $dbh->do ($sql); @@ -212,6 +227,7 @@ sub upgrade { # Perform the actual upgrade. if ($self->{schema}->get_db_version) { $self->{schema}->upgrade_directory ($Wallet::Config::DB_DDL_DIRECTORY); + #use Data::Dumper; warn Dumper $self->{schema}; eval { $self->{schema}->upgrade; }; } if ($@) { diff --git a/perl/lib/Wallet/Object/Base.pm b/perl/lib/Wallet/Object/Base.pm index bf535e98..6be511df 100644 --- a/perl/lib/Wallet/Object/Base.pm +++ b/perl/lib/Wallet/Object/Base.pm @@ -24,6 +24,8 @@ use Wallet::ACL; our $VERSION = '1.04'; +my $TZ = DateTime::TimeZone->new( name => 'local' ); + ############################################################################## # Constructors ############################################################################## @@ -60,7 +62,7 @@ sub create { die "invalid object name\n" unless $name; my $guard = $schema->txn_scope_guard; eval { - my $date = DateTime->from_epoch (epoch => $time); + my $date = DateTime->from_epoch (epoch => $time, time_zone => $TZ); my %record = (ob_type => $type, ob_name => $name, ob_created_by => $user, @@ -134,7 +136,7 @@ sub log_action { # assume that AutoCommit is turned off. my $guard = $self->{schema}->txn_scope_guard; eval { - my $date = DateTime->from_epoch (epoch => $time); + my $date = DateTime->from_epoch (epoch => $time, time_zone => $TZ); my %record = (oh_type => $self->{type}, oh_name => $self->{name}, oh_action => $action, @@ -188,7 +190,7 @@ sub log_set { die "invalid history field $field"; } - my $date = DateTime->from_epoch (epoch => $time); + my $date = DateTime->from_epoch (epoch => $time, time_zone => $TZ); my %record = (oh_type => $self->{type}, oh_name => $self->{name}, oh_action => 'set', @@ -353,7 +355,7 @@ sub expires { $self->error ("malformed expiration time $expires"); return; } - my $date = DateTime->from_epoch (epoch => $seconds); + my $date = DateTime->from_epoch (epoch => $seconds, time_zone => $TZ); return $self->_set_internal ('expires', $date, $user, $host, $time); } elsif (defined $expires) { return $self->_set_internal ('expires', undef, $user, $host, $time); @@ -743,7 +745,7 @@ sub destroy { $self->{schema}->resultset('Object')->search (\%search)->delete; # And create a new history object for the destroy action. - my $date = DateTime->from_epoch (epoch => $time); + my $date = DateTime->from_epoch (epoch => $time, time_zone => $TZ); my %record = (oh_type => $type, oh_name => $name, oh_action => 'destroy', diff --git a/perl/lib/Wallet/Report.pm b/perl/lib/Wallet/Report.pm index 151a2858..7163f161 100644 --- a/perl/lib/Wallet/Report.pm +++ b/perl/lib/Wallet/Report.pm @@ -504,7 +504,8 @@ sub acls_unused { } # Obtain a textual representation of the membership of an ACL, returning undef -# on error and setting the internal error. +# on error and setting the internal error. Make sure the membership is sorted +# so that comparisons are possible. sub acl_membership { my ($self, $id) = @_; my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) }; @@ -512,7 +513,9 @@ sub acl_membership { $self->error ($@); return; } - my @members = map { "$_->[0] $_->[1]" } $acl->list; + my @entries = $acl->list; + my @entries_sorted = sort { $$a[0] cmp $$b[0] or $$a[1] cmp $$b[1] } @entries; + my @members = map { "$_->[0] $_->[1]" } @entries_sorted; if (!@members && $acl->error) { $self->error ($acl->error); return; diff --git a/perl/lib/Wallet/Schema.pm b/perl/lib/Wallet/Schema.pm index f75fda86..cd04f2e8 100644 --- a/perl/lib/Wallet/Schema.pm +++ b/perl/lib/Wallet/Schema.pm @@ -20,7 +20,7 @@ use base 'DBIx::Class::Schema'; # Unlike all of the other wallet modules, this module's version is tied to the # version of the schema in the database. It should only be changed on schema # changes, at least until better handling of upgrades is available. -our $VERSION = '0.10'; +our $VERSION = '0.11'; __PACKAGE__->load_namespaces; __PACKAGE__->load_components (qw/Schema::Versioned/); @@ -50,6 +50,7 @@ sub connect { my $user = $Wallet::Config::DB_USER; my $pass = $Wallet::Config::DB_PASSWORD; my %attrs = (PrintError => 0, RaiseError => 1); + my $schema = eval { $class->SUPER::connect ($dsn, $user, $pass, \%attrs) }; if ($@) { die "cannot connect to database: $@\n"; diff --git a/perl/lib/Wallet/Schema/Result/Acl.pm b/perl/lib/Wallet/Schema/Result/Acl.pm index 9a73b185..f907bc4f 100644 --- a/perl/lib/Wallet/Schema/Result/Acl.pm +++ b/perl/lib/Wallet/Schema/Result/Acl.pm @@ -42,6 +42,12 @@ __PACKAGE__->table("acls"); is_nullable: 0 size: 255 +=head2 ac_comment + + data_type: 'varchar' + is_nullable: 1 + size: 255 + =cut __PACKAGE__->add_columns( @@ -49,6 +55,8 @@ __PACKAGE__->add_columns( { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, "ac_name", { data_type => "varchar", is_nullable => 0, size => 255 }, + "ac_comment", + { data_type => "varchar", is_nullable => 1, size => 255 }, ); __PACKAGE__->set_primary_key("ac_id"); __PACKAGE__->add_unique_constraint("ac_name", ["ac_name"]); diff --git a/perl/lib/Wallet/Server.pm b/perl/lib/Wallet/Server.pm index af0d8a8f..a923571b 100644 --- a/perl/lib/Wallet/Server.pm +++ b/perl/lib/Wallet/Server.pm @@ -633,6 +633,32 @@ sub acl_check { return 1; } +# Retrieves or sets the comment of an ACL. We don't record comment changes +# to the ACL history table. +sub acl_comment { + my ($self, $id, $comment) = @_; + unless ($self->{admin}->check ($self->{user})) { + $self->acl_error ($id, 'comment'); + return; + } + my $acl = eval { Wallet::ACL->new ($id, $self->{schema}) }; + if ($@) { + $self->error ($@); + return; + } + + my $result; + if (defined $comment) { + $result = $acl->set_comment ($comment); + } else { + return $acl->get_comment(); + } + if (not defined ($result) and $acl->error) { + $self->error ($acl->error); + } + return $result; +} + # Create a new empty ACL in the database. Returns true on success and undef # on failure, setting the internal error. sub acl_create { diff --git a/perl/sql/Wallet-Schema-0.10-0.11-MySQL.sql b/perl/sql/Wallet-Schema-0.10-0.11-MySQL.sql new file mode 100644 index 00000000..88969c56 --- /dev/null +++ b/perl/sql/Wallet-Schema-0.10-0.11-MySQL.sql @@ -0,0 +1,9 @@ +-- Convert schema 'sql/Wallet-Schema-0.10-MySQL.sql' to 'Wallet::Schema v0.11':; + +BEGIN; + +ALTER TABLE acls ADD COLUMN ac_comment varchar(255); + +COMMIT; + + diff --git a/perl/sql/Wallet-Schema-0.10-0.11-PostgreSQL.sql b/perl/sql/Wallet-Schema-0.10-0.11-PostgreSQL.sql new file mode 100644 index 00000000..f0c1bf9d --- /dev/null +++ b/perl/sql/Wallet-Schema-0.10-0.11-PostgreSQL.sql @@ -0,0 +1,8 @@ +-- Convert schema 'sql/Wallet-Schema-0.10-PostgreSQL.sql' to 'sql/Wallet-Schema-0.11-PostgreSQL.sql':; + +BEGIN; + +ALTER TABLE acls ADD COLUMN ac_comment character varying(255) NULL; + +COMMIT; + diff --git a/perl/sql/Wallet-Schema-0.10-0.11-SQLite.sql b/perl/sql/Wallet-Schema-0.10-0.11-SQLite.sql new file mode 100644 index 00000000..3c840071 --- /dev/null +++ b/perl/sql/Wallet-Schema-0.10-0.11-SQLite.sql @@ -0,0 +1,7 @@ +-- Convert schema 'sql/Wallet-Schema-0.10-SQLite.sql' to 'sql/Wallet-Schema-0.11-SQLite.sql':; + +BEGIN; + +ALTER TABLE acls ADD ac_comment varchar(255) default null; + +COMMIT; diff --git a/perl/sql/Wallet-Schema-0.11-MySQL.sql b/perl/sql/Wallet-Schema-0.11-MySQL.sql new file mode 100644 index 00000000..04831aa8 --- /dev/null +++ b/perl/sql/Wallet-Schema-0.11-MySQL.sql @@ -0,0 +1,216 @@ +-- +-- Created by SQL::Translator::Producer::MySQL +-- Created on Thu Oct 9 20:54:55 2014 +-- +-- Copyright 2014 +-- The Board of Trustees of the Leland Stanford Junior University +-- +-- SPDX-License-Identifier: MIT +-- + +SET foreign_key_checks=0; + +DROP TABLE IF EXISTS `acl_history`; + +-- +-- Table: `acl_history` +-- +CREATE TABLE `acl_history` ( + `ah_id` integer NOT NULL auto_increment, + `ah_acl` integer NOT NULL, + `ah_name` varchar(255) NULL, + `ah_action` varchar(16) NOT NULL, + `ah_scheme` varchar(32) NULL, + `ah_identifier` varchar(255) NULL, + `ah_by` varchar(255) NOT NULL, + `ah_from` varchar(255) NOT NULL, + `ah_on` datetime NOT NULL, + INDEX `acl_history_idx_ah_acl` (`ah_acl`), + INDEX `acl_history_idx_ah_name` (`ah_name`), + PRIMARY KEY (`ah_id`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci; + +DROP TABLE IF EXISTS `acl_schemes`; + +-- +-- Table: `acl_schemes` +-- +CREATE TABLE `acl_schemes` ( + `as_name` varchar(32) NOT NULL, + `as_class` varchar(64) NULL, + PRIMARY KEY (`as_name`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci ENGINE=InnoDB; + +DROP TABLE IF EXISTS `acls`; + +-- +-- Table: `acls` +-- +CREATE TABLE `acls` ( + `ac_id` integer NOT NULL auto_increment, + `ac_name` varchar(255) NOT NULL, + `ac_comment` varchar(255) NULL, + PRIMARY KEY (`ac_id`), + UNIQUE `ac_name` (`ac_name`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci ENGINE=InnoDB; + +DROP TABLE IF EXISTS `enctypes`; + +-- +-- Table: `enctypes` +-- +CREATE TABLE `enctypes` ( + `en_name` varchar(255) NOT NULL, + PRIMARY KEY (`en_name`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci; + +DROP TABLE IF EXISTS `flags`; + +-- +-- Table: `flags` +-- +CREATE TABLE `flags` ( + `fl_type` varchar(16) NOT NULL, + `fl_name` varchar(255) NOT NULL, + `fl_flag` enum('locked', 'unchanging') NOT NULL, + PRIMARY KEY (`fl_type`, `fl_name`, `fl_flag`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci; + +DROP TABLE IF EXISTS `keytab_enctypes`; + +-- +-- Table: `keytab_enctypes` +-- +CREATE TABLE `keytab_enctypes` ( + `ke_name` varchar(255) NOT NULL, + `ke_enctype` varchar(255) NOT NULL, + PRIMARY KEY (`ke_name`, `ke_enctype`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci; + +DROP TABLE IF EXISTS `keytab_sync`; + +-- +-- Table: `keytab_sync` +-- +CREATE TABLE `keytab_sync` ( + `ks_name` varchar(255) NOT NULL, + `ks_target` varchar(255) NOT NULL, + PRIMARY KEY (`ks_name`, `ks_target`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci; + +DROP TABLE IF EXISTS `object_history`; + +-- +-- Table: `object_history` +-- +CREATE TABLE `object_history` ( + `oh_id` integer NOT NULL auto_increment, + `oh_type` varchar(16) NOT NULL, + `oh_name` varchar(255) NOT NULL, + `oh_action` varchar(16) NOT NULL, + `oh_field` varchar(16) NULL, + `oh_type_field` varchar(255) NULL, + `oh_old` varchar(255) NULL, + `oh_new` varchar(255) NULL, + `oh_by` varchar(255) NOT NULL, + `oh_from` varchar(255) NOT NULL, + `oh_on` datetime NOT NULL, + INDEX `object_history_idx_oh_type_oh_name` (`oh_type`, `oh_name`), + PRIMARY KEY (`oh_id`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci; + +DROP TABLE IF EXISTS `sync_targets`; + +-- +-- Table: `sync_targets` +-- +CREATE TABLE `sync_targets` ( + `st_name` varchar(255) NOT NULL, + PRIMARY KEY (`st_name`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci; + +DROP TABLE IF EXISTS `types`; + +-- +-- Table: `types` +-- +CREATE TABLE `types` ( + `ty_name` varchar(16) NOT NULL, + `ty_class` varchar(64) NULL, + PRIMARY KEY (`ty_name`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci ENGINE=InnoDB; + +DROP TABLE IF EXISTS `acl_entries`; + +-- +-- Table: `acl_entries` +-- +CREATE TABLE `acl_entries` ( + `ae_id` integer NOT NULL, + `ae_scheme` varchar(32) NOT NULL, + `ae_identifier` varchar(255) NOT NULL, + INDEX `acl_entries_idx_ae_scheme` (`ae_scheme`), + INDEX `acl_entries_idx_ae_id` (`ae_id`), + PRIMARY KEY (`ae_id`, `ae_scheme`, `ae_identifier`), + CONSTRAINT `acl_entries_fk_ae_scheme` FOREIGN KEY (`ae_scheme`) REFERENCES `acl_schemes` (`as_name`), + CONSTRAINT `acl_entries_fk_ae_id` FOREIGN KEY (`ae_id`) REFERENCES `acls` (`ac_id`) ON DELETE CASCADE ON UPDATE CASCADE +) CHARACTER SET latin1 COLLATE latin1_swedish_ci ENGINE=InnoDB; + +DROP TABLE IF EXISTS `objects`; + +-- +-- Table: `objects` +-- +CREATE TABLE `objects` ( + `ob_type` varchar(16) NOT NULL, + `ob_name` varchar(255) NOT NULL, + `ob_owner` integer NULL, + `ob_acl_get` integer NULL, + `ob_acl_store` integer NULL, + `ob_acl_show` integer NULL, + `ob_acl_destroy` integer NULL, + `ob_acl_flags` integer NULL, + `ob_expires` datetime NULL, + `ob_created_by` varchar(255) NOT NULL, + `ob_created_from` varchar(255) NOT NULL, + `ob_created_on` datetime NOT NULL, + `ob_stored_by` varchar(255) NULL, + `ob_stored_from` varchar(255) NULL, + `ob_stored_on` datetime NULL, + `ob_downloaded_by` varchar(255) NULL, + `ob_downloaded_from` varchar(255) NULL, + `ob_downloaded_on` datetime NULL, + `ob_comment` varchar(255) NULL, + INDEX `objects_idx_ob_acl_destroy` (`ob_acl_destroy`), + INDEX `objects_idx_ob_acl_flags` (`ob_acl_flags`), + INDEX `objects_idx_ob_acl_get` (`ob_acl_get`), + INDEX `objects_idx_ob_owner` (`ob_owner`), + INDEX `objects_idx_ob_acl_show` (`ob_acl_show`), + INDEX `objects_idx_ob_acl_store` (`ob_acl_store`), + INDEX `objects_idx_ob_type` (`ob_type`), + PRIMARY KEY (`ob_name`, `ob_type`), + CONSTRAINT `objects_fk_ob_acl_destroy` FOREIGN KEY (`ob_acl_destroy`) REFERENCES `acls` (`ac_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `objects_fk_ob_acl_flags` FOREIGN KEY (`ob_acl_flags`) REFERENCES `acls` (`ac_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `objects_fk_ob_acl_get` FOREIGN KEY (`ob_acl_get`) REFERENCES `acls` (`ac_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `objects_fk_ob_owner` FOREIGN KEY (`ob_owner`) REFERENCES `acls` (`ac_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `objects_fk_ob_acl_show` FOREIGN KEY (`ob_acl_show`) REFERENCES `acls` (`ac_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `objects_fk_ob_acl_store` FOREIGN KEY (`ob_acl_store`) REFERENCES `acls` (`ac_id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `objects_fk_ob_type` FOREIGN KEY (`ob_type`) REFERENCES `types` (`ty_name`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci ENGINE=InnoDB; + +DROP TABLE IF EXISTS `duo`; + +-- +-- Table: `duo` +-- +CREATE TABLE `duo` ( + `du_name` varchar(255) NOT NULL, + `du_type` varchar(16) NOT NULL, + `du_key` varchar(255) NOT NULL, + INDEX `duo_idx_du_type_du_name` (`du_type`, `du_name`), + PRIMARY KEY (`du_name`, `du_type`), + CONSTRAINT `duo_fk_du_type_du_name` FOREIGN KEY (`du_type`, `du_name`) REFERENCES `objects` (`ob_type`, `ob_name`) +) CHARACTER SET latin1 COLLATE latin1_swedish_ci ENGINE=InnoDB; + +SET foreign_key_checks=1; + diff --git a/perl/sql/Wallet-Schema-0.11-PostgreSQL.sql b/perl/sql/Wallet-Schema-0.11-PostgreSQL.sql new file mode 100644 index 00000000..efcd7499 --- /dev/null +++ b/perl/sql/Wallet-Schema-0.11-PostgreSQL.sql @@ -0,0 +1,223 @@ +-- +-- Created by SQL::Translator::Producer::PostgreSQL +-- Created on Thu Oct 9 20:54:56 2014 +-- +-- Copyright 2014 +-- The Board of Trustees of the Leland Stanford Junior University +-- +-- SPDX-License-Identifier: MIT +-- + +-- +-- Table: acl_history. +-- +DROP TABLE IF EXISTS "acl_history" CASCADE; +CREATE TABLE "acl_history" ( + "ah_id" serial NOT NULL, + "ah_acl" integer NOT NULL, + "ah_name" character varying(255), + "ah_action" character varying(16) NOT NULL, + "ah_scheme" character varying(32), + "ah_identifier" character varying(255), + "ah_by" character varying(255) NOT NULL, + "ah_from" character varying(255) NOT NULL, + "ah_on" timestamp NOT NULL, + PRIMARY KEY ("ah_id") +); +CREATE INDEX "acl_history_idx_ah_acl" on "acl_history" ("ah_acl"); +CREATE INDEX "acl_history_idx_ah_name" on "acl_history" ("ah_name"); + +-- +-- Table: acl_schemes. +-- +DROP TABLE IF EXISTS "acl_schemes" CASCADE; +CREATE TABLE "acl_schemes" ( + "as_name" character varying(32) NOT NULL, + "as_class" character varying(64), + PRIMARY KEY ("as_name") +); + +-- +-- Table: acls. +-- +DROP TABLE IF EXISTS "acls" CASCADE; +CREATE TABLE "acls" ( + "ac_id" serial NOT NULL, + "ac_name" character varying(255) NOT NULL, + "ac_comment" character varying(255), + PRIMARY KEY ("ac_id"), + CONSTRAINT "ac_name" UNIQUE ("ac_name") +); + +-- +-- Table: enctypes. +-- +DROP TABLE IF EXISTS "enctypes" CASCADE; +CREATE TABLE "enctypes" ( + "en_name" character varying(255) NOT NULL, + PRIMARY KEY ("en_name") +); + +-- +-- Table: flags. +-- +DROP TABLE IF EXISTS "flags" CASCADE; +CREATE TABLE "flags" ( + "fl_type" character varying(16) NOT NULL, + "fl_name" character varying(255) NOT NULL, + "fl_flag" character varying NOT NULL, + PRIMARY KEY ("fl_type", "fl_name", "fl_flag") +); + +-- +-- Table: keytab_enctypes. +-- +DROP TABLE IF EXISTS "keytab_enctypes" CASCADE; +CREATE TABLE "keytab_enctypes" ( + "ke_name" character varying(255) NOT NULL, + "ke_enctype" character varying(255) NOT NULL, + PRIMARY KEY ("ke_name", "ke_enctype") +); + +-- +-- Table: keytab_sync. +-- +DROP TABLE IF EXISTS "keytab_sync" CASCADE; +CREATE TABLE "keytab_sync" ( + "ks_name" character varying(255) NOT NULL, + "ks_target" character varying(255) NOT NULL, + PRIMARY KEY ("ks_name", "ks_target") +); + +-- +-- Table: object_history. +-- +DROP TABLE IF EXISTS "object_history" CASCADE; +CREATE TABLE "object_history" ( + "oh_id" serial NOT NULL, + "oh_type" character varying(16) NOT NULL, + "oh_name" character varying(255) NOT NULL, + "oh_action" character varying(16) NOT NULL, + "oh_field" character varying(16), + "oh_type_field" character varying(255), + "oh_old" character varying(255), + "oh_new" character varying(255), + "oh_by" character varying(255) NOT NULL, + "oh_from" character varying(255) NOT NULL, + "oh_on" timestamp NOT NULL, + PRIMARY KEY ("oh_id") +); +CREATE INDEX "object_history_idx_oh_type_oh_name" on "object_history" ("oh_type", "oh_name"); + +-- +-- Table: sync_targets. +-- +DROP TABLE IF EXISTS "sync_targets" CASCADE; +CREATE TABLE "sync_targets" ( + "st_name" character varying(255) NOT NULL, + PRIMARY KEY ("st_name") +); + +-- +-- Table: types. +-- +DROP TABLE IF EXISTS "types" CASCADE; +CREATE TABLE "types" ( + "ty_name" character varying(16) NOT NULL, + "ty_class" character varying(64), + PRIMARY KEY ("ty_name") +); + +-- +-- Table: acl_entries. +-- +DROP TABLE IF EXISTS "acl_entries" CASCADE; +CREATE TABLE "acl_entries" ( + "ae_id" integer NOT NULL, + "ae_scheme" character varying(32) NOT NULL, + "ae_identifier" character varying(255) NOT NULL, + PRIMARY KEY ("ae_id", "ae_scheme", "ae_identifier") +); +CREATE INDEX "acl_entries_idx_ae_scheme" on "acl_entries" ("ae_scheme"); +CREATE INDEX "acl_entries_idx_ae_id" on "acl_entries" ("ae_id"); + +-- +-- Table: objects. +-- +DROP TABLE IF EXISTS "objects" CASCADE; +CREATE TABLE "objects" ( + "ob_type" character varying(16) NOT NULL, + "ob_name" character varying(255) NOT NULL, + "ob_owner" integer, + "ob_acl_get" integer, + "ob_acl_store" integer, + "ob_acl_show" integer, + "ob_acl_destroy" integer, + "ob_acl_flags" integer, + "ob_expires" timestamp, + "ob_created_by" character varying(255) NOT NULL, + "ob_created_from" character varying(255) NOT NULL, + "ob_created_on" timestamp NOT NULL, + "ob_stored_by" character varying(255), + "ob_stored_from" character varying(255), + "ob_stored_on" timestamp, + "ob_downloaded_by" character varying(255), + "ob_downloaded_from" character varying(255), + "ob_downloaded_on" timestamp, + "ob_comment" character varying(255), + PRIMARY KEY ("ob_name", "ob_type") +); +CREATE INDEX "objects_idx_ob_acl_destroy" on "objects" ("ob_acl_destroy"); +CREATE INDEX "objects_idx_ob_acl_flags" on "objects" ("ob_acl_flags"); +CREATE INDEX "objects_idx_ob_acl_get" on "objects" ("ob_acl_get"); +CREATE INDEX "objects_idx_ob_owner" on "objects" ("ob_owner"); +CREATE INDEX "objects_idx_ob_acl_show" on "objects" ("ob_acl_show"); +CREATE INDEX "objects_idx_ob_acl_store" on "objects" ("ob_acl_store"); +CREATE INDEX "objects_idx_ob_type" on "objects" ("ob_type"); + +-- +-- Table: duo. +-- +DROP TABLE IF EXISTS "duo" CASCADE; +CREATE TABLE "duo" ( + "du_name" character varying(255) NOT NULL, + "du_type" character varying(16) NOT NULL, + "du_key" character varying(255) NOT NULL, + PRIMARY KEY ("du_name", "du_type") +); +CREATE INDEX "duo_idx_du_type_du_name" on "duo" ("du_type", "du_name"); + +-- +-- Foreign Key Definitions +-- + +ALTER TABLE "acl_entries" ADD CONSTRAINT "acl_entries_fk_ae_scheme" FOREIGN KEY ("ae_scheme") + REFERENCES "acl_schemes" ("as_name") DEFERRABLE; + +ALTER TABLE "acl_entries" ADD CONSTRAINT "acl_entries_fk_ae_id" FOREIGN KEY ("ae_id") + REFERENCES "acls" ("ac_id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +ALTER TABLE "objects" ADD CONSTRAINT "objects_fk_ob_acl_destroy" FOREIGN KEY ("ob_acl_destroy") + REFERENCES "acls" ("ac_id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +ALTER TABLE "objects" ADD CONSTRAINT "objects_fk_ob_acl_flags" FOREIGN KEY ("ob_acl_flags") + REFERENCES "acls" ("ac_id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +ALTER TABLE "objects" ADD CONSTRAINT "objects_fk_ob_acl_get" FOREIGN KEY ("ob_acl_get") + REFERENCES "acls" ("ac_id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +ALTER TABLE "objects" ADD CONSTRAINT "objects_fk_ob_owner" FOREIGN KEY ("ob_owner") + REFERENCES "acls" ("ac_id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +ALTER TABLE "objects" ADD CONSTRAINT "objects_fk_ob_acl_show" FOREIGN KEY ("ob_acl_show") + REFERENCES "acls" ("ac_id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +ALTER TABLE "objects" ADD CONSTRAINT "objects_fk_ob_acl_store" FOREIGN KEY ("ob_acl_store") + REFERENCES "acls" ("ac_id") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE; + +ALTER TABLE "objects" ADD CONSTRAINT "objects_fk_ob_type" FOREIGN KEY ("ob_type") + REFERENCES "types" ("ty_name") DEFERRABLE; + +ALTER TABLE "duo" ADD CONSTRAINT "duo_fk_du_type_du_name" FOREIGN KEY ("du_type", "du_name") + REFERENCES "objects" ("ob_type", "ob_name") DEFERRABLE; + diff --git a/perl/sql/Wallet-Schema-0.11-SQLite.sql b/perl/sql/Wallet-Schema-0.11-SQLite.sql new file mode 100644 index 00000000..4071598b --- /dev/null +++ b/perl/sql/Wallet-Schema-0.11-SQLite.sql @@ -0,0 +1,226 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Thu Oct 9 20:51:25 2014 +-- +-- Copyright 2014 +-- The Board of Trustees of the Leland Stanford Junior University +-- +-- SPDX-License-Identifier: MIT +-- + +BEGIN TRANSACTION; + +-- +-- Table: acl_history +-- +DROP TABLE IF EXISTS acl_history; + +CREATE TABLE acl_history ( + ah_id INTEGER PRIMARY KEY NOT NULL, + ah_acl integer NOT NULL, + ah_name varchar(255), + ah_action varchar(16) NOT NULL, + ah_scheme varchar(32), + ah_identifier varchar(255), + ah_by varchar(255) NOT NULL, + ah_from varchar(255) NOT NULL, + ah_on datetime NOT NULL +); + +CREATE INDEX acl_history_idx_ah_acl ON acl_history (ah_acl); + +CREATE INDEX acl_history_idx_ah_name ON acl_history (ah_name); + +-- +-- Table: acl_schemes +-- +DROP TABLE IF EXISTS acl_schemes; + +CREATE TABLE acl_schemes ( + as_name varchar(32) NOT NULL, + as_class varchar(64), + PRIMARY KEY (as_name) +); + +-- +-- Table: acls +-- +DROP TABLE IF EXISTS acls; + +CREATE TABLE acls ( + ac_id INTEGER PRIMARY KEY NOT NULL, + ac_name varchar(255) NOT NULL, + ac_comment varchar(255) +); + +CREATE UNIQUE INDEX ac_name ON acls (ac_name); + +-- +-- Table: enctypes +-- +DROP TABLE IF EXISTS enctypes; + +CREATE TABLE enctypes ( + en_name varchar(255) NOT NULL, + PRIMARY KEY (en_name) +); + +-- +-- Table: flags +-- +DROP TABLE IF EXISTS flags; + +CREATE TABLE flags ( + fl_type varchar(16) NOT NULL, + fl_name varchar(255) NOT NULL, + fl_flag enum NOT NULL, + PRIMARY KEY (fl_type, fl_name, fl_flag) +); + +-- +-- Table: keytab_enctypes +-- +DROP TABLE IF EXISTS keytab_enctypes; + +CREATE TABLE keytab_enctypes ( + ke_name varchar(255) NOT NULL, + ke_enctype varchar(255) NOT NULL, + PRIMARY KEY (ke_name, ke_enctype) +); + +-- +-- Table: keytab_sync +-- +DROP TABLE IF EXISTS keytab_sync; + +CREATE TABLE keytab_sync ( + ks_name varchar(255) NOT NULL, + ks_target varchar(255) NOT NULL, + PRIMARY KEY (ks_name, ks_target) +); + +-- +-- Table: object_history +-- +DROP TABLE IF EXISTS object_history; + +CREATE TABLE object_history ( + oh_id INTEGER PRIMARY KEY NOT NULL, + oh_type varchar(16) NOT NULL, + oh_name varchar(255) NOT NULL, + oh_action varchar(16) NOT NULL, + oh_field varchar(16), + oh_type_field varchar(255), + oh_old varchar(255), + oh_new varchar(255), + oh_by varchar(255) NOT NULL, + oh_from varchar(255) NOT NULL, + oh_on datetime NOT NULL +); + +CREATE INDEX object_history_idx_oh_type_oh_name ON object_history (oh_type, oh_name); + +-- +-- Table: sync_targets +-- +DROP TABLE IF EXISTS sync_targets; + +CREATE TABLE sync_targets ( + st_name varchar(255) NOT NULL, + PRIMARY KEY (st_name) +); + +-- +-- Table: types +-- +DROP TABLE IF EXISTS types; + +CREATE TABLE types ( + ty_name varchar(16) NOT NULL, + ty_class varchar(64), + PRIMARY KEY (ty_name) +); + +-- +-- Table: acl_entries +-- +DROP TABLE IF EXISTS acl_entries; + +CREATE TABLE acl_entries ( + ae_id integer NOT NULL, + ae_scheme varchar(32) NOT NULL, + ae_identifier varchar(255) NOT NULL, + PRIMARY KEY (ae_id, ae_scheme, ae_identifier), + FOREIGN KEY (ae_scheme) REFERENCES acl_schemes(as_name), + FOREIGN KEY (ae_id) REFERENCES acls(ac_id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX acl_entries_idx_ae_scheme ON acl_entries (ae_scheme); + +CREATE INDEX acl_entries_idx_ae_id ON acl_entries (ae_id); + +-- +-- Table: objects +-- +DROP TABLE IF EXISTS objects; + +CREATE TABLE objects ( + ob_type varchar(16) NOT NULL, + ob_name varchar(255) NOT NULL, + ob_owner integer, + ob_acl_get integer, + ob_acl_store integer, + ob_acl_show integer, + ob_acl_destroy integer, + ob_acl_flags integer, + ob_expires datetime, + ob_created_by varchar(255) NOT NULL, + ob_created_from varchar(255) NOT NULL, + ob_created_on datetime NOT NULL, + ob_stored_by varchar(255), + ob_stored_from varchar(255), + ob_stored_on datetime, + ob_downloaded_by varchar(255), + ob_downloaded_from varchar(255), + ob_downloaded_on datetime, + ob_comment varchar(255), + PRIMARY KEY (ob_name, ob_type), + FOREIGN KEY (ob_acl_destroy) REFERENCES acls(ac_id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (ob_acl_flags) REFERENCES acls(ac_id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (ob_acl_get) REFERENCES acls(ac_id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (ob_owner) REFERENCES acls(ac_id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (ob_acl_show) REFERENCES acls(ac_id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (ob_acl_store) REFERENCES acls(ac_id) ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY (ob_type) REFERENCES types(ty_name) +); + +CREATE INDEX objects_idx_ob_acl_destroy ON objects (ob_acl_destroy); + +CREATE INDEX objects_idx_ob_acl_flags ON objects (ob_acl_flags); + +CREATE INDEX objects_idx_ob_acl_get ON objects (ob_acl_get); + +CREATE INDEX objects_idx_ob_owner ON objects (ob_owner); + +CREATE INDEX objects_idx_ob_acl_show ON objects (ob_acl_show); + +CREATE INDEX objects_idx_ob_acl_store ON objects (ob_acl_store); + +CREATE INDEX objects_idx_ob_type ON objects (ob_type); + +-- +-- Table: duo +-- +DROP TABLE IF EXISTS duo; + +CREATE TABLE duo ( + du_name varchar(255) NOT NULL, + du_type varchar(16) NOT NULL, + du_key varchar(255) NOT NULL, + PRIMARY KEY (du_name, du_type), + FOREIGN KEY (du_type, du_name) REFERENCES objects(ob_type, ob_name) +); + +CREATE INDEX duo_idx_du_type_du_name ON duo (du_type, du_name); + +COMMIT; diff --git a/perl/t/general/acl.t b/perl/t/general/acl.t index c6e33f97..ebc4b7df 100755 --- a/perl/t/general/acl.t +++ b/perl/t/general/acl.t @@ -12,10 +12,11 @@ use strict; use warnings; use POSIX qw(strftime); -use Test::More tests => 115; +use Test::More tests => 122; use Wallet::ACL; use Wallet::Admin; +use Wallet::Config; use Wallet::Object::Base; use lib 't/lib'; @@ -27,14 +28,21 @@ my $user1 = 'alice@EXAMPLE.COM'; my $user2 = 'bob@EXAMPLE.COM'; my $host = 'localhost'; my @trace = ($admin, $host, time); +my $TZ = DateTime::TimeZone->new( name => 'local' ); -# Use Wallet::Admin to set up the database. +# Use Wallet::Admin to set up the database. This setup destroys the +# database, so we turn off version checking during the initial setup since +# we are ging to be destroying the tables anyway. This avoids some +# unpleasant unversioned schema errors. +# DBIx::Class::Schema::Versioned::_on_connect(): Your DB is currently unversioned. db_setup; -my $setup = eval { Wallet::Admin->new }; +my $setup = setup_initialize(); is ($@, '', 'Database connection succeeded'); -is ($setup->reinitialize ($setup), 1, 'Database initialization succeeded'); +is ($setup->reinitialize ($admin), 1, 'Database initialization succeeded'); my $schema = $setup->schema; +# #### ## #### ## #### ## #### ## #### ## #### ## #### ## #### # + # Test create and new. my $acl = eval { Wallet::ACL->create ('test', $schema, @trace) }; ok (defined ($acl), 'ACL creation'); @@ -134,7 +142,7 @@ is ($entries[1][0], 'krb5', ' and the right scheme for 2'); is ($entries[1][1], $user2, ' and the right identifier for 2'); $expected = <<"EOE"; Members of ACL test (id: 2) are: - krb5 + krb5 krb5 $user2 EOE is ($acl->show, $expected, ' and show returns correctly'); @@ -165,7 +173,7 @@ is ($acl->show, "Members of ACL test (id: 2) are:\n", ' and show concurs'); is ($acl->check ($user2), 0, ' and the second user check fails'); is (scalar ($acl->check_errors), '', ' with no error message'); -# Test rename. +# Test nesting. my $acl_nest = eval { Wallet::ACL->create ('test-nesting', $schema, @trace) }; ok (defined ($acl_nest), 'ACL creation for setting up nested'); if ($acl_nest->add ('nested', 'test', @trace)) { @@ -173,6 +181,8 @@ if ($acl_nest->add ('nested', 'test', @trace)) { } else { is ($acl_nest->error, '', ' and adding the nesting'); } + +# Test rename. Rename if ($acl->rename ('example', @trace)) { ok (1, 'Renaming the ACL'); } else { @@ -201,7 +211,7 @@ like ($acl->error, qr/^cannot rename ACL example to ADMIN: /, is ($entries[0][1], 'example', ' and the name in a nested ACL updated'); # Test history. -my $date = strftime ('%Y-%m-%d %H:%M:%S', localtime $trace[2]); +my $date = DateTime->from_epoch(epoch => $trace[2], time_zone => $TZ)->strftime('%Y-%m-%d %H:%M:%S'); my $history = <<"EOO"; $date create by $admin from $host @@ -211,11 +221,11 @@ $date add krb5 $user2 by $admin from $host $date remove krb5 $user1 by $admin from $host -$date add krb5 +$date add krb5 by $admin from $host $date remove krb5 $user2 by $admin from $host -$date remove krb5 +$date remove krb5 by $admin from $host $date rename from test by $admin from $host @@ -248,7 +258,10 @@ $acl = eval { Wallet::ACL->create ('example', $schema, @trace) }; ok (defined ($acl), ' and creating another with the same name works'); is ($@, '', ' with no exceptions'); is ($acl->name, 'example', ' and the right name'); -like ($acl->id, qr{\A[34]\z}, ' and an ID of 3 or 4'); +# Keep in mind that when testing against MySQL failed inserts use up auto-incremented +# primary keys. Thus, the id for this acl in MySQL will be larger than in +# SQLite. Thuse we allow this id to be wither 4 or 5. +like ($acl->id, qr{\A[45]\z}, ' and an ID of 4 or 5'); # 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 @@ -308,6 +321,37 @@ is ($obj_new->owner, 'example-new', is ($obj_unrelated->owner, 'example-other', ' and unrelated object ownership is correct'); +# Test ACL comments. +my $comment; +$acl = eval { Wallet::ACL->create ('test-comment', $schema, @trace) }; +ok (defined ($acl), 'ACL creation for setting up comment'); +if (!defined($acl->comment)) { + ok (1, ' new ACL has no comment defined'); +} else { + is ($acl->error, undef, ' new ACL has no comment defined'); +} +$comment = 'this is an ACL comment'; +if ($acl->set_comment($comment)) { + ok (1, ' added ACL comment'); +} else { + is ($acl->error, 1, ' added ACL comment'); +} +ok (($acl->comment() eq $comment), ' store ACL comment correctly'); +$comment = q{}; +if ($acl->set_comment($comment)) { + ok (1, ' added ACL comment'); +} else { + is ($acl->error, 1, ' added ACL comment'); +} +ok (!defined($acl->comment()), ' stored empty ACL comment correctly'); + +# Test a long comment; should raise an exception. +$comment = '0' x 259 ; +eval { ($acl->set_comment($comment)) } ; +is ($acl->error, 'comment cannot be longer than 255 characters'); + +$acl->destroy (@trace); + # Clean up. $setup->destroy; END { diff --git a/perl/t/general/admin.t b/perl/t/general/admin.t index a2045583..de49ce9c 100755 --- a/perl/t/general/admin.t +++ b/perl/t/general/admin.t @@ -24,7 +24,7 @@ use Util; # We test database setup in init.t, so just do the basic setup here. db_setup; -my $admin = eval { Wallet::Admin->new }; +my $admin = setup_initialize(); is ($@, '', 'Wallet::Admin creation did not die'); ok ($admin->isa ('Wallet::Admin'), ' and returned the right class'); is ($admin->initialize ('admin@EXAMPLE.COM'), 1, @@ -70,18 +70,20 @@ SKIP: { my @path = (split (':', $ENV{PATH})); my ($sqlite) = grep { -x $_ } map { "$_/sqlite3" } @path; skip 'sqlite3 not found', 7 unless $sqlite; - # Delete all tables and then redump them straight from the SQL file to # avoid getting the version table. - unlink 'wallet-db'; + db_setup_sqlite(); + my $status = system ('sqlite3', 'wallet-db', '.read sql/Wallet-Schema-0.07-SQLite.sql'); - is ($status, 0, 'Reinstalling database from non-versioned SQL succeds'); + is ($status, 0, 'Reinstalling database from non-versioned SQL succeeds'); + # Upgrade to 0.08. $Wallet::Schema::VERSION = '0.08'; - $admin = eval { Wallet::Admin->new }; + $admin = setup_initialize(); my $retval = $admin->upgrade; + is ($retval, 1, ' and performing an upgrade to 0.08 succeeds'); my $sql = "select version from dbix_class_schema_versions order by" . " version DESC"; diff --git a/perl/t/general/init.t b/perl/t/general/init.t index ddc4aa13..5f00200f 100755 --- a/perl/t/general/init.t +++ b/perl/t/general/init.t @@ -21,12 +21,11 @@ use Util; # Use Wallet::Admin to set up the database. db_setup; -my $admin = eval { Wallet::Admin->new }; +my $admin = setup_initialize(); is ($@, '', 'Wallet::Admin creation did not die'); ok ($admin->isa ('Wallet::Admin'), ' and returned the right class'); -is ($admin->initialize ('admin@EXAMPLE.COM'), 1, +is ($admin->reinitialize ('admin@EXAMPLE.COM'), 1, ' and initialization succeeds'); - # Check whether the database entries that should be created were. my $acl = eval { Wallet::ACL->new ('ADMIN', $admin->schema) }; is ($@, '', 'Retrieving ADMIN ACL successful'); diff --git a/perl/t/general/report.t b/perl/t/general/report.t index 8b491f59..48bd0e24 100755 --- a/perl/t/general/report.t +++ b/perl/t/general/report.t @@ -22,13 +22,14 @@ use Util; # Use Wallet::Admin to set up the database. db_setup; -my $admin = eval { Wallet::Admin->new }; +my $admin = setup_initialize(); is ($@, '', 'Wallet::Admin creation did not die'); is ($admin->reinitialize ('admin@EXAMPLE.COM'), 1, 'Database initialization succeeded'); $admin->register_object ('base', 'Wallet::Object::Base'); $admin->register_verifier ('base', 'Wallet::ACL::Base'); + # We have an empty database, so we should see no objects and one ACL. my $report = eval { Wallet::Report->new }; is ($@, '', 'Wallet::Report creation did not die'); @@ -41,6 +42,7 @@ is (scalar (@acls), 1, 'One ACL in the database'); is ($acls[0][0], 1, ' and that is ACL ID 1'); is ($acls[0][1], 'ADMIN', ' with the right name'); + # Check to see that we have all types that we expect. my @types = $report->types; is (scalar (@types), 10, 'There are ten types created'); @@ -350,7 +352,6 @@ is (scalar (@acls), 1, 'There is one set of duplicate ACLs'); is (scalar (@{ $acls[0] }), 2, ' with two members'); is ($acls[0][0], 'fourth', ' and the first member is correct'); is ($acls[0][1], 'third', ' and the second member is correct'); - # Add another line to the third ACL. Now we match second. is ($server->acl_add ('third', 'base', 'foo'), 1, 'Adding another line to the third ACL works'); diff --git a/perl/t/general/server.t b/perl/t/general/server.t index 0794f158..4142a5b9 100755 --- a/perl/t/general/server.t +++ b/perl/t/general/server.t @@ -31,7 +31,7 @@ my @trace = ($admin, $host); # Use Wallet::Admin to set up the database. db_setup; -my $setup = eval { Wallet::Admin->new }; +my $setup = setup_initialize(); is ($@, '', 'Database initialization did not die'); is ($setup->reinitialize ($admin), 1, 'Database initialization succeeded'); @@ -45,6 +45,14 @@ ok (defined ($schema), ' and returns a defined schema object'); # Allow creation of base objects for testing purposes. $setup->register_object ('base', 'Wallet::Object::Base'); +# ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### # +sub get_acl_id { + my ($acl_name) = @_; + my $acl_temp = Wallet::ACL->new ($acl_name, $schema); + return $acl_temp->id; +} +# ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### ## ### # + # We're currently running as the administrator, so everything should succeed. # Set up a bunch of data for us to test with, starting with some ACLs. Test # the error handling while we're at it. @@ -114,8 +122,10 @@ is ($server->acl_add ('user2', 'krb5', $user2), 1, 'Add another entry'); is ($server->acl_add ('both', 'krb5', $user1), 1, ' and another'); is ($server->acl_add ('both', 'krb5', $user2), 1, ' and another to the same ACL'); +my $acl_both_id = get_acl_id('both'); +my $acl_user2_id = get_acl_id('user2'); is ($server->acl_show ('both'), - "Members of ACL both (id: 4) are:\n krb5 $user1\n krb5 $user2\n", + "Members of ACL both (id: $acl_both_id) are:\n krb5 $user1\n krb5 $user2\n", ' and show returns the correct result'); $history = <<"EOO"; DATE create @@ -140,8 +150,9 @@ is ($server->acl_remove ('empty', 'krb5', $user2), undef, is ($server->error, "cannot remove krb5:$user2 from empty: entry not found in ACL", ' and returns the right error'); +my $acl_empty_id = get_acl_id('empty'); is ($server->acl_show ('empty'), - "Members of ACL empty (id: 6) are:\n krb5 $user1\n", + "Members of ACL empty (id: $acl_empty_id) are:\n krb5 $user1\n", ' and show returns the correct status'); is ($server->acl_remove ('empty', 'krb5', $user1), 1, ' but removing a good one works'); @@ -150,7 +161,7 @@ is ($server->acl_remove ('empty', 'krb5', $user1), undef, is ($server->error, "cannot remove krb5:$user1 from empty: entry not found in ACL", ' and returns the right error'); -is ($server->acl_show ('empty'), "Members of ACL empty (id: 6) are:\n", +is ($server->acl_show ('empty'), "Members of ACL empty (id: $acl_empty_id) are:\n", ' and show returns the correct status'); # Make sure we can't cripple the ADMIN ACL. @@ -437,11 +448,11 @@ DATE unset acl_store (was ADMIN (1)) by $admin from $host DATE set owner to ADMIN (1) by $admin from $host -DATE set acl_get to empty (6) +DATE set acl_get to empty ($acl_empty_id) by $admin from $host -DATE set acl_store to empty (6) +DATE set acl_store to empty ($acl_empty_id) by $admin from $host -DATE unset acl_store (was empty (6)) +DATE unset acl_store (was empty ($acl_empty_id)) by $admin from $host DATE unset owner (was ADMIN (1)) by $admin from $host @@ -630,25 +641,25 @@ $expected = <<"EOO"; Created from: $host Created on: 0 -Members of ACL both (id: 4) are: +Members of ACL both (id: $acl_both_id) are: krb5 $user1 krb5 $user2 Members of ACL user1 (id: 2) are: krb5 $user1 -Members of ACL user2 (id: 3) are: +Members of ACL user2 (id: $acl_user2_id) are: krb5 $user2 EOO is ($show, $expected, ' and show an object we jointly own'); $history = <<"EOO"; DATE create by $admin from $host -DATE set owner to both (4) +DATE set owner to both ($acl_both_id) by $admin from $host DATE set acl_show to user1 (2) by $admin from $host -DATE set acl_destroy to user2 (3) +DATE set acl_destroy to user2 ($acl_user2_id) by $admin from $host DATE set acl_flags to user1 (2) by $admin from $host @@ -708,14 +719,14 @@ $expected = <<"EOO"; Created from: $host Created on: 0 -Members of ACL user2 (id: 3) are: +Members of ACL user2 (id: $acl_user2_id) are: krb5 $user2 EOO is ($show, $expected, ' and show an object we own'); $history = <<"EOO"; DATE create by $admin from $host -DATE set owner to user2 (3) +DATE set owner to user2 ($acl_user2_id) by $admin from $host EOO $seen = $server->history ('base', 'service/user2'); @@ -856,6 +867,7 @@ is ($server->autocreate ('base', 'service/foo'), undef, is ($server->error, "$user2 not authorized to create base:service/foo", ' with the right error'); $show = $server->show ('base', 'service/default'); +my $acl_default_id = get_acl_id('default'); if (defined $show) { $show =~ s/(Created on:) [\d-]+ [\d:]+$/$1 0/m; $expected = <<"EOO"; @@ -866,7 +878,7 @@ if (defined $show) { Created from: $host Created on: 0 -Members of ACL default (id: 7) are: +Members of ACL default (id: $acl_default_id) are: krb5 $user1 krb5 $user2 EOO @@ -892,7 +904,7 @@ $expected = <<"EOO"; Created from: $host Created on: 0 -Members of ACL user2 (id: 3) are: +Members of ACL user2 (id: $acl_user2_id) are: krb5 $user2 EOO is ($show, $expected, ' and the created object and ACL are correct'); @@ -915,6 +927,7 @@ is ($server->autocreate ('base', 'service/default-admin'), 1, 'Autocreation works for admin'); $show = $server->show ('base', 'service/default-admin'); $show =~ s/(Created on:) [\d-]+ [\d:]+$/$1 0/m; +my $acl_autoadmin_id = get_acl_id('auto-admin'); $expected = <<"EOO"; Type: base Name: service/default-admin @@ -923,7 +936,7 @@ $expected = <<"EOO"; Created from: $host Created on: 0 -Members of ACL auto-admin (id: 8) are: +Members of ACL auto-admin (id: $acl_autoadmin_id) are: krb5 $admin EOO is ($show, $expected, ' and the created object and ACL are correct'); @@ -1027,6 +1040,7 @@ END { unlink 'wallet-db'; } +local $ENV{DBIC_NO_VERSION_CHECK} = 1; # Now test handling of some configuration errors. undef $Wallet::Config::DB_DRIVER; $server = eval { Wallet::Server->new ($user2, $host) }; @@ -1041,3 +1055,4 @@ $Wallet::Config::DB_INFO = 't'; $server = eval { Wallet::Server->new ($user2, $host) }; like ($@, qr/unable to open database file/, ' or if the database connection fails'); + diff --git a/perl/t/lib/Util.pm b/perl/t/lib/Util.pm index c5833736..e221f2bb 100644 --- a/perl/t/lib/Util.pm +++ b/perl/t/lib/Util.pm @@ -23,7 +23,7 @@ $VERSION = '0.03'; use Exporter (); @ISA = qw(Exporter); @EXPORT = qw(contents db_setup getcreds keytab_valid remctld_spawn - remctld_stop); + remctld_stop setup_initialize db_setup_sqlite); ############################################################################## # General utility functions @@ -49,28 +49,45 @@ sub contents { sub db_setup { $Wallet::Config::DB_DDL_DIRECTORY = 'sql/'; if (-f 't/data/test.database') { - open (DB, '<', 't/data/test.database') - or die "cannot open t/data/test.database: $!"; - my $driver = ; - my $info = ; - my $user = ; - my $password = ; - chomp ($driver, $info); - chomp $user if $user; - chomp $password if $password; - $Wallet::Config::DB_DRIVER = $driver; - $Wallet::Config::DB_INFO = $info; - $Wallet::Config::DB_USER = $user if $user; - $Wallet::Config::DB_PASSWORD = $password if $password; + db_setup_from_test_database(); } else { + db_setup_sqlite(); + } +} - # If we have a new SQLite db by default, disable version checking. - $ENV{DBIC_NO_VERSION_CHECK} = 1; +sub db_setup_from_test_database { + open (DB, '<', 't/data/test.database') + or die "cannot open t/data/test.database: $!"; + my $driver = ; + my $info = ; + my $user = ; + my $password = ; + chomp ($driver, $info); + chomp $user if $user; + chomp $password if $password; + $Wallet::Config::DB_DRIVER = $driver; + $Wallet::Config::DB_INFO = $info; + $Wallet::Config::DB_USER = $user if $user; + $Wallet::Config::DB_PASSWORD = $password if $password; +} - $Wallet::Config::DB_DRIVER = 'SQLite'; - $Wallet::Config::DB_INFO = 'wallet-db'; - unlink 'wallet-db'; - } +sub db_setup_sqlite { + # If we have a new SQLite db by default, disable version checking. + $ENV{DBIC_NO_VERSION_CHECK} = 1; + + $Wallet::Config::DB_DRIVER = 'SQLite'; + $Wallet::Config::DB_INFO = 'wallet-db'; + unlink 'wallet-db'; +} + + +sub setup_initialize { + my $admin; + eval { + local $ENV{DBIC_NO_VERSION_CHECK} = 1; + $admin = Wallet::Admin->new; + }; + return $admin ; } ############################################################################## diff --git a/perl/t/object/base.t b/perl/t/object/base.t index 2126ebf6..02407673 100755 --- a/perl/t/object/base.t +++ b/perl/t/object/base.t @@ -30,7 +30,7 @@ my $princ = 'service/test@EXAMPLE.COM'; # Use Wallet::Admin to set up the database. db_setup; -my $admin = eval { Wallet::Admin->new }; +my $admin = setup_initialize(); is ($@, '', 'Database connection succeeded'); is ($admin->reinitialize ($user), 1, 'Database initialization succeeded'); my $schema = $admin->schema; diff --git a/perl/t/object/file.t b/perl/t/object/file.t index 80173cd3..2d9a87e1 100755 --- a/perl/t/object/file.t +++ b/perl/t/object/file.t @@ -32,7 +32,7 @@ $| = 1; # Use Wallet::Admin to set up the database. system ('rm -rf test-files') == 0 or die "cannot remove test-files\n"; db_setup; -my $admin = eval { Wallet::Admin->new }; +my $admin = setup_initialize(); is ($@, '', 'Database connection succeeded'); is ($admin->reinitialize ($user), 1, 'Database initialization succeeded'); my $schema = $admin->schema; diff --git a/perl/t/object/keytab.t b/perl/t/object/keytab.t index dfb96bdb..e3cf78e9 100755 --- a/perl/t/object/keytab.t +++ b/perl/t/object/keytab.t @@ -160,7 +160,7 @@ sub enctypes { # Use Wallet::Admin to set up the database. unlink ('krb5cc_temp', 'krb5cc_test', 'test-acl', 'test-pid'); db_setup; -my $admin = eval { Wallet::Admin->new }; +my $admin = setup_initialize(); is ($@, '', 'Database connection succeeded'); is ($admin->reinitialize ($user), 1, 'Database initialization succeeded'); my $schema = $admin->schema; diff --git a/perl/t/object/password.t b/perl/t/object/password.t index 72a818ce..628fc798 100644 --- a/perl/t/object/password.t +++ b/perl/t/object/password.t @@ -33,7 +33,7 @@ $| = 1; # Use Wallet::Admin to set up the database. system ('rm -rf test-files') == 0 or die "cannot remove test-files\n"; db_setup; -my $admin = eval { Wallet::Admin->new }; +my $admin = setup_initialize(); is ($@, '', 'Database connection succeeded'); is ($admin->reinitialize ($user), 1, 'Database initialization succeeded'); my $schema = $admin->schema; diff --git a/perl/t/verifier/nested.t b/perl/t/verifier/nested.t index a975ea35..f7464866 100755 --- a/perl/t/verifier/nested.t +++ b/perl/t/verifier/nested.t @@ -31,9 +31,9 @@ my @trace = ($admin, $host, time); # Use Wallet::Admin to set up the database. db_setup; -my $setup = eval { Wallet::Admin->new }; +my $setup = setup_initialize(); is ($@, '', 'Database connection succeeded'); -is ($setup->reinitialize ($setup), 1, 'Database initialization succeeded'); +is ($setup->reinitialize ($admin), 1, 'Database initialization succeeded'); my $schema = $setup->schema; # Create a few ACLs for later testing. diff --git a/server/wallet-backend.in b/server/wallet-backend.in index 8e384607..868474fe 100644 --- a/server/wallet-backend.in +++ b/server/wallet-backend.in @@ -154,6 +154,20 @@ sub command { } elsif ($action eq 'create') { check_args (1, 1, [], @args); $server->acl_create (@args) or failure ($server->error, @_); + } elsif ($action eq 'comment') { + check_args (1, 2, [2], @args); + if (@args > 1) { + $server->acl_comment (@args) or failure ($server->error, @_); + } else { + my $output = $server->acl_comment (@args); + if (defined $output) { + print $output, "\n"; + } elsif (not $server->error) { + print "No comment set\n"; + } else { + failure ($server->error, @_); + } + } } elsif ($action eq 'destroy') { check_args (1, 1, [], @args); $server->acl_destroy (@args) or failure ($server->error, @_); @@ -427,6 +441,15 @@ either the name of an ACL or its numeric identifier. Check whether an ACL with the ID already exists. If it does, prints C; if not, prints C. +=item acl comment [] + +If is not given, displays the current comment for the ACL +identified by and , or C if none is set. + +If is given, sets the comment on the ACL identified by + to . If is the empty string, clears +the comment. + =item acl create Create a new, empty ACL with name . When setting an ACL on an @@ -444,7 +467,7 @@ be destroyed. =item acl history Display the history of the ACL . Each change to the ACL (not -including changes to the name of the ACL) will be represented by two +including changes to the name or comment of the ACL) will be represented by two lines. The first line will have a timestamp of the change followed by a description of the change, and the second line will give the user who made the change and the host from which the change was made. @@ -479,7 +502,7 @@ the C ACL. =item acl show -Display the name, numeric ID, and entries of the ACL . +Display the name, numeric ID, comment, and entries of the ACL . =item autocreate