diff options
author | Russ Allbery <rra@stanford.edu> | 2008-01-23 03:33:41 +0000 |
---|---|---|
committer | Russ Allbery <rra@stanford.edu> | 2008-01-23 03:33:41 +0000 |
commit | 77b6875f95aa54fe9c648ba114e06d85cf655bb1 (patch) | |
tree | 27a3ce2238ed38894e68ef7242a3b2a71c5e6cdc /perl | |
parent | d94cac7f73b8a0c0a067bc179747426726ab8c31 (diff) |
Refactor database initialization into a new Wallet::Admin module.
Diffstat (limited to 'perl')
-rw-r--r-- | perl/Wallet/Admin.pm | 193 | ||||
-rw-r--r-- | perl/Wallet/Server.pm | 55 | ||||
-rwxr-xr-x | perl/t/acl.t | 13 | ||||
-rwxr-xr-x | perl/t/init.t | 28 | ||||
-rwxr-xr-x | perl/t/keytab.t | 12 | ||||
-rwxr-xr-x | perl/t/object.t | 14 | ||||
-rwxr-xr-x | perl/t/server.t | 10 |
7 files changed, 234 insertions, 91 deletions
diff --git a/perl/Wallet/Admin.pm b/perl/Wallet/Admin.pm new file mode 100644 index 0000000..400068d --- /dev/null +++ b/perl/Wallet/Admin.pm @@ -0,0 +1,193 @@ +# Wallet::Admin -- Wallet system administrative interface. +# $Id$ +# +# Written by Russ Allbery <rra@stanford.edu> +# Copyright 2008 Board of Trustees, Leland Stanford Jr. University +# +# See LICENSE for licensing terms. + +############################################################################## +# Modules and declarations +############################################################################## + +package Wallet::Admin; +require 5.006; + +use strict; +use vars qw($VERSION); + +use Wallet::ACL; +use Wallet::Database; +use Wallet::Schema; + +# 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.01'; + +############################################################################## +# Constructor, destructor, and accessors +############################################################################## + +# Create a new wallet administrator object. Opens a connection to the +# database that will be used for all of the wallet configuration information. +# Throw an exception if anything goes wrong. +sub new { + my ($class) = @_; + my $dbh = Wallet::Database->connect; + my $self = { dbh => $dbh }; + bless ($self, $class); + return $self; +} + +# Returns the database handle (used mostly for testing). +sub dbh { + my ($self) = @_; + return $self->{dbh}; +} + +# Set or return the error stashed in the object. +sub error { + my ($self, @error) = @_; + if (@error) { + my $error = join ('', @error); + chomp $error; + 1 while ($error =~ s/ at \S+ line \d+\.?\z//); + $self->{error} = $error; + } + return $self->{error}; +} + +# Disconnect the database handle on object destruction to avoid warnings. +sub DESTROY { + my ($self) = @_; + $self->{dbh}->disconnect unless $self->{dbh}->{InactiveDestroy}; +} + +############################################################################## +# Database initialization +############################################################################## + +# Initializes the database by populating it with our schema and then creates +# and returns a new wallet server object. This is used only for initial +# database creation. Takes the Kerberos principal who will be the default +# administrator so that we can create an initial administrator ACL. Returns +# true on success and false on failure, setting the object error. +sub initialize { + my ($self, $user) = @_; + my $schema = Wallet::Schema->new; + eval { $schema->create ($self->{dbh}) }; + if ($@) { + $self->error ($@); + return; + } + my $acl = Wallet::ACL->create ('ADMIN', $self->{dbh}, $user, 'localhost'); + unless ($acl->add ('krb5', $user, $user, 'localhost')) { + $self->error ($acl->error); + return; + } + return 1; +} + +# The same as initialize, but also drops any existing tables first before +# creating the schema. Takes the same arguments and throws an exception on +# failure. +sub reinitialize { + my ($self, $user) = @_; + my $schema = Wallet::Schema->new; + eval { $schema->drop ($self->{dbh}) }; + if ($@) { + $self->error ($@); + return; + } + return $self->initialize ($user); +} + +1; +__DATA__ + +############################################################################## +# Documentation +############################################################################## + +=head1 NAME + +Wallet::Admin - Wallet system administrative interface + +=head1 SYNOPSIS + + use Wallet::Admin; + my $admin = Wallet::Admin->new; + unless ($admin->initialize ('user/admin@EXAMPLE.COM')) { + die $admin->error; + } + +=head1 DESCRIPTION + +Wallet::Admin implements the administrative interface to the wallet server +and database. It is normally instantiated and used by B<wallet-admin>, a +thin wrapper around this object that provides a command-line interface to +its actions. + +To use this object, several configuration variables must be set (at least +the database configuration). For information on those variables and how to +set them, see Wallet::Config(3). For more information on the normal user +interface to the wallet server, see Wallet::Server(3). + +=head1 CLASS METHODS + +=over 4 + +=item new() + +Creates a new wallet administrative object and connects to the database. +On any error, this method throws an exception. + +=back + +=head1 INSTANCE METHODS + +For all methods that can fail, the caller should call error() after a +failure to get the error message. + +=over 4 + +=item initialize(PRINCIPAL) + +Initializes the database as configured in Wallet::Config and loads the +wallet database schema. Then, creates an ACL with the name ADMIN and adds +an ACL entry of scheme C<krb5> and instance PRINCIPAL to that ACL. This +bootstraps the authorization system and lets that Kerberos identity make +further changes to the ADMIN ACL and the rest of the wallet database. + +initialize() uses C<localhost> as the hostname and PRINCIPAL as the user +when logging the history of the ADMIN ACL creation and for any subsequent +actions on the object it returns. + +=item error() + +Returns the error of the last failing operation or undef if no operations +have failed. Callers should call this function to get the error message +after an undef return from any other instance method. + +=item reinitialize(PRINCIPAL) + +Performs the same actions as initialize(), but first drops any existing +wallet database tables from the database, allowing this function to be +called on a prior wallet database. All data stored in the database will +be deleted and a fresh set of wallet database tables will be created. + +=back + +=head1 SEE ALSO + +wallet-admin(8) + +This module is part of the wallet system. The current version is available +from L<http://www.eyrie.org/~eagle/software/wallet/>. + +=head1 AUTHOR + +Russ Allbery <rra@stanford.edu> + +=cut diff --git a/perl/Wallet/Server.pm b/perl/Wallet/Server.pm index 68add52..96cff15 100644 --- a/perl/Wallet/Server.pm +++ b/perl/Wallet/Server.pm @@ -30,36 +30,6 @@ $VERSION = '0.06'; # Utility methods ############################################################################## -# Initializes the database by populating it with our schema and then creates -# and returns a new wallet server object. This is used only for initial -# database creation. Takes the Kerberos principal who will be the default -# administrator so that we can create an initial administrator ACL. Throws an -# exception on failure. -sub initialize { - my ($class, $user) = @_; - my $dbh = Wallet::Database->connect; - my $schema = Wallet::Schema->new; - $schema->create ($dbh); - my $acl = Wallet::ACL->create ('ADMIN', $dbh, $user, 'localhost'); - unless ($acl->add ('krb5', $user, $user, 'localhost')) { - die "$@\n"; - } - $dbh->disconnect; - return $class->new ($user, 'localhost'); -} - -# The same as initialize, but also drops any existing tables first before -# creating the schema. Takes the same arguments and throws an exception on -# failure. -sub reinitialize { - my ($class, $user) = @_; - my $dbh = Wallet::Database->connect; - my $schema = Wallet::Schema->new; - $schema->drop ($dbh); - $dbh->disconnect; - return $class->initialize ($user); -} - # Create a new wallet server object. A new server should be created for each # user who is making changes to the wallet. Takes the principal and host who # are sending wallet requests. Opens a connection to the database that will @@ -738,22 +708,6 @@ set them, see Wallet::Config(3). =over 4 -=item initialize(PRINCIPAL) - -Initializes the database as configured in Wallet::Config and loads the -wallet database schema. Then, creates an ACL with the name ADMIN and adds -an ACL entry of scheme C<krb5> and instance PRINCIPAL to that ACL. This -bootstraps the authorization system and lets that Kerberos identity make -further changes to the ADMIN ACL and the rest of the wallet database. -Returns a new Wallet::Server object, although that object should only be -used to do other administrative functions. Before performing normal -operations, that object should be destroyed and the database reopened with -new(). initialize() uses C<localhost> as the hostname and PRINCIPAL as the -user when logging the history of the ADMIN ACL creation and for any -subsequent actions on the object it returns. - -On any error, this method throws an exception. - =item new(PRINCIPAL, HOSTNAME) Creates a new wallet server object for actions from the user PRINCIPAL @@ -765,15 +719,6 @@ privileged operations. On any error, this method throws an exception. -=item reinitialize(PRINCIPAL) - -Performs the same actions as initialize(), but first drops any existing -wallet database tables from the database, allowing this function to be -called on a prior wallet database. All data stored in the database will be -deleted and a fresh set of wallet database tables will be created. - -On any error, this method throws an exception. - =back =head1 INSTANCE METHODS diff --git a/perl/t/acl.t b/perl/t/acl.t index 16af5c1..15796d2 100755 --- a/perl/t/acl.t +++ b/perl/t/acl.t @@ -4,7 +4,7 @@ # t/api.t -- Tests for the wallet ACL API. # # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2007 Board of Trustees, Leland Stanford Jr. University +# Copyright 2007, 2008 Board of Trustees, Leland Stanford Jr. University # # See LICENSE for licensing terms. @@ -12,6 +12,7 @@ use POSIX qw(strftime); use Test::More tests => 101; use Wallet::ACL; +use Wallet::Admin; use Wallet::Config; use Wallet::Server; @@ -25,12 +26,12 @@ my $user2 = 'bob@EXAMPLE.COM'; my $host = 'localhost'; my @trace = ($admin, $host, time); -# Use Wallet::Server to set up the database. +# Use Wallet::Admin to set up the database. db_setup; -my $server = eval { Wallet::Server->reinitialize ($admin) }; -is ($@, '', 'Database initialization did not die'); -ok ($server->isa ('Wallet::Server'), ' and returned the right class'); -my $dbh = $server->dbh; +my $setup = eval { Wallet::Admin->new }; +is ($@, '', 'Database connection succeeded'); +is ($setup->reinitialize ($setup), 1, 'Database initialization succeeded'); +my $dbh = $setup->dbh; # Test create and new. my $acl = eval { Wallet::ACL->create ('test', $dbh, @trace) }; diff --git a/perl/t/init.t b/perl/t/init.t index 18f8e3b..9e1b600 100755 --- a/perl/t/init.t +++ b/perl/t/init.t @@ -4,27 +4,30 @@ # t/init.t -- Tests for database initialization. # # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2007 Board of Trustees, Leland Stanford Jr. University +# Copyright 2007, 2008 Board of Trustees, Leland Stanford Jr. University # # See LICENSE for licensing terms. use Test::More tests => 16; use Wallet::ACL; +use Wallet::Admin; +use Wallet::Admin; use Wallet::Config; -use Wallet::Server; use lib 't/lib'; use Util; -# Use Wallet::Server to set up the database. +# Use Wallet::Admin to set up the database. db_setup; -my $server = eval { Wallet::Server->initialize ('admin@EXAMPLE.COM') }; -is ($@, '', 'Database initialization did not die'); -ok ($server->isa ('Wallet::Server'), ' and returned the right class'); +my $admin = eval { Wallet::Admin->new }; +is ($@, '', 'Wallet::Admin creation did not die'); +ok ($admin->isa ('Wallet::Admin'), ' and returned the right class'); +is ($admin->initialize ('admin@EXAMPLE.COM'), 1, + ' and initialization succeeds'); # Check whether the database entries that should be created were. -my $acl = eval { Wallet::ACL->new ('ADMIN', $server->dbh) }; +my $acl = eval { Wallet::ACL->new ('ADMIN', $admin->dbh) }; is ($@, '', 'Retrieving ADMIN ACL successful'); ok ($acl->isa ('Wallet::ACL'), ' and is the right class'); my @entries = $acl->list; @@ -34,21 +37,20 @@ is ($entries[0][0], 'krb5', ' of krb5 scheme'); is ($entries[0][1], 'admin@EXAMPLE.COM', ' with the right user'); # Test reinitialization. -$server = eval { Wallet::Server->reinitialize ('admin@EXAMPLE.COM') }; -is ($@, '', 'Reinitialization did not die'); -ok ($server->isa ('Wallet::Server'), ' and returned the right class'); +is ($admin->reinitialize ('admin@EXAMPLE.ORG'), 1, + 'Reinitialization succeeded'); # Now repeat the database content checks. -$acl = eval { Wallet::ACL->new ('ADMIN', $server->dbh) }; +$acl = eval { Wallet::ACL->new ('ADMIN', $admin->dbh) }; is ($@, '', 'Retrieving ADMIN ACL successful'); ok ($acl->isa ('Wallet::ACL'), ' and is the right class'); @entries = $acl->list; is (scalar (@entries), 1, ' and has only one entry'); isnt ($entries[0], undef, ' which is a valid entry'); is ($entries[0][0], 'krb5', ' of krb5 scheme'); -is ($entries[0][1], 'admin@EXAMPLE.COM', ' with the right user'); +is ($entries[0][1], 'admin@EXAMPLE.ORG', ' with the right user'); # Clean up. my $schema = Wallet::Schema->new; -$schema->drop ($server->dbh); +$schema->drop ($admin->dbh); unlink 'wallet-db'; diff --git a/perl/t/keytab.t b/perl/t/keytab.t index bb6b048..a40332a 100755 --- a/perl/t/keytab.t +++ b/perl/t/keytab.t @@ -11,9 +11,9 @@ use POSIX qw(strftime); use Test::More tests => 223; +use Wallet::Admin; use Wallet::Config; use Wallet::Object::Keytab; -use Wallet::Server; use lib 't/lib'; use Util; @@ -187,13 +187,13 @@ sub stop_remctld { kill 15, $pid; } -# Use Wallet::Server to set up the database. +# Use Wallet::Admin to set up the database. unlink ('krb5cc_temp', 'krb5cc_test', 'test-acl', 'test-pid'); db_setup; -my $server = eval { Wallet::Server->reinitialize ($user) }; -is ($@, '', 'Database initialization did not die'); -ok ($server->isa ('Wallet::Server'), ' and returned the right class'); -my $dbh = $server->dbh; +my $admin = eval { Wallet::Admin->new }; +is ($@, '', 'Database connection succeeded'); +is ($admin->reinitialize ($user), 1, 'Database initialization succeeded'); +my $dbh = $admin->dbh; # Use this to accumulate the history traces so that we can check history. my $history = ''; diff --git a/perl/t/object.t b/perl/t/object.t index 101110a..48604bc 100755 --- a/perl/t/object.t +++ b/perl/t/object.t @@ -4,7 +4,7 @@ # t/object.t -- Tests for the basic object implementation. # # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2007 Board of Trustees, Leland Stanford Jr. University +# Copyright 2007, 2008 Board of Trustees, Leland Stanford Jr. University # # See LICENSE for licensing terms. @@ -12,9 +12,9 @@ use POSIX qw(strftime); use Test::More tests => 131; use Wallet::ACL; +use Wallet::Admin; use Wallet::Config; use Wallet::Object::Base; -use Wallet::Server; use lib 't/lib'; use Util; @@ -25,12 +25,12 @@ my $host = 'localhost'; my @trace = ($user, $host, time); my $princ = 'service/test@EXAMPLE.COM'; -# Use Wallet::Server to set up the database. +# Use Wallet::Admin to set up the database. db_setup; -my $server = eval { Wallet::Server->reinitialize ($user) }; -is ($@, '', 'Database initialization did not die'); -ok ($server->isa ('Wallet::Server'), ' and returned the right class'); -my $dbh = $server->dbh; +my $admin = eval { Wallet::Admin->new }; +is ($@, '', 'Database connection succeeded'); +is ($admin->reinitialize ($user), 1, 'Database initialization succeeded'); +my $dbh = $admin->dbh; # Okay, now we have a database. Test create and new. We make believe this is # a keytab object; it won't matter for what we're doing. diff --git a/perl/t/server.t b/perl/t/server.t index 893f23a..5378969 100755 --- a/perl/t/server.t +++ b/perl/t/server.t @@ -11,6 +11,7 @@ use Test::More tests => 332; use POSIX qw(strftime); +use Wallet::Admin; use Wallet::Config; use Wallet::Schema; use Wallet::Server; @@ -25,13 +26,14 @@ my $user2 = 'bob@EXAMPLE.COM'; my $host = 'localhost'; my @trace = ($admin, $host); -# Use Wallet::Server to set up the database. +# Use Wallet::Admin to set up the database. db_setup; -my $server = eval { Wallet::Server->initialize ($admin) }; +my $setup = eval { Wallet::Admin->new }; is ($@, '', 'Database initialization did not die'); -ok ($server->isa ('Wallet::Server'), ' and returned the right class'); +is ($setup->reinitialize ($admin), 1, 'Database initialization succeeded'); +undef $setup; -# Now test the new method as well. +# Now test the new method. $server = eval { Wallet::Server->new (@trace) }; is ($@, '', 'Reopening with new did not die'); ok ($server->isa ('Wallet::Server'), ' and returned the right class'); |