diff options
| author | Russ Allbery <rra@stanford.edu> | 2007-12-05 01:10:23 +0000 | 
|---|---|---|
| committer | Russ Allbery <rra@stanford.edu> | 2007-12-05 01:10:23 +0000 | 
| commit | c0c34051887d08a94221f9cbc2b74fbfad34c22c (patch) | |
| tree | cf6dbd65beee76296f4a16fef21c86419eaa5ed8 | |
| parent | 0e9a5e25ec9c1977c6426f4aea4b61a658fe6855 (diff) | |
Determine the class for object and ACL schema implementations from the
database rather than a hard-coded list and provide Wallet::Schema
methods for adding new class mappings.
Add a missing class mapping for the netdb ACL schema verifier.
| -rw-r--r-- | NEWS | 6 | ||||
| -rw-r--r-- | TODO | 10 | ||||
| -rw-r--r-- | perl/Wallet/ACL.pm | 35 | ||||
| -rw-r--r-- | perl/Wallet/Schema.pm | 62 | ||||
| -rw-r--r-- | perl/Wallet/Server.pm | 35 | ||||
| -rwxr-xr-x | perl/t/schema.t | 2 | ||||
| -rwxr-xr-x | perl/t/server.t | 10 | 
7 files changed, 126 insertions, 34 deletions
| @@ -6,6 +6,12 @@ wallet 0.4 (unreleased)      have an instance of "root" and strips that instance before checking      NetDB roles. +    Determine the class for object and ACL schema implementations from the +    database rather than a hard-coded list and provide Wallet::Schema +    methods for adding new class mappings. + +    Add a missing class mapping for the netdb ACL schema verifier. +  wallet 0.3 (2007-12-03)      MySQL is now a supported database backend and the full test suite @@ -6,9 +6,6 @@ Release 0.4:  * Write the PTS ACL verifier. -* Use the class names in the database tables when loading object and -  ACL verifier implementations. -  Release 1.0:  * Add POD testing for the client and server programs. @@ -67,8 +64,11 @@ Release 1.0:  * On upgrades, support adding new object types and ACL verifiers to the    class tables. -* Write a wallet-admin program to provide an interface to things like -  database initialization and, eventually, upgrades. +* Write a wallet-admin program and a corresponding Wallet::Admin class to +  provide an interface to things like database initialization and, +  eventually, upgrades.  Move the methods to add additional class mappings +  from Wallet::Schema to Wallet::Admin and the initialize and reinitialize +  methods from Wallet::Server to Wallet::Admin.  * Implement store support in the wallet client.  Add an option to read the    data from a file.  The initial implementation, depending on the diff --git a/perl/Wallet/ACL.pm b/perl/Wallet/ACL.pm index 12b3f7c..d654e68 100644 --- a/perl/Wallet/ACL.pm +++ b/perl/Wallet/ACL.pm @@ -14,7 +14,7 @@ package Wallet::ACL;  require 5.006;  use strict; -use vars qw(%MAPPING $VERSION); +use vars qw($VERSION);  use DBI;  use POSIX qw(strftime); @@ -23,13 +23,7 @@ use Wallet::ACL::Krb5;  # 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.02'; - -# This is a mapping of schemes to class names, used to determine which ACL -# verifier should be instantiated for a given ACL scheme.  Currently, there's -# no dynamic way to recognize new ACL verifiers, so if you extend the wallet -# system to add new verifiers, you need to modify this list. -%MAPPING = (krb5 => 'Wallet::ACL::Krb5'); +$VERSION = '0.03';  ##############################################################################  # Constructors @@ -134,6 +128,24 @@ sub name {      return $self->{name};  } +# Given an ACL scheme, return the mapping to a class by querying the +# database, or undef if no mapping exists. +sub scheme_mapping { +    my ($self, $scheme) = @_; +    my $class; +    eval { +        my $sql = 'select as_class from acl_schemes where as_name = ?'; +        ($class) = $self->{dbh}->selectrow_array ($sql, undef, $scheme); +        $self->{dbh}->commit; +    }; +    if ($@) { +        $self->error ($@); +        $self->{dbh}->rollback; +        return; +    } +    return $class; +} +  # Record a change to an ACL.  Takes the type of change, the scheme and  # identifier of the entry, and the trace information (user, host, and time).  # This function does not commit and does not catch exceptions.  It should @@ -209,7 +221,7 @@ sub destroy {  sub add {      my ($self, $scheme, $identifier, $user, $host, $time) = @_;      $time ||= time; -    unless ($MAPPING{$scheme}) { +    unless ($self->scheme_mapping ($scheme)) {          $self->error ("unknown ACL scheme $scheme");          return undef;      } @@ -359,11 +371,12 @@ sub check {      for my $entry (@entries) {          my ($scheme, $identifier) = @$entry;          unless ($verifier{$scheme}) { -            unless ($MAPPING{$scheme}) { +            my $class = $self->scheme_mapping ($scheme); +            unless ($class) {                  push (@{ $self->{check_errors} }, "unknown scheme $scheme");                  next;              } -            $verifier{$scheme} = ($MAPPING{$scheme})->new; +            $verifier{$scheme} = $class->new;              unless (defined $verifier{$scheme}) {                  push (@{ $self->{check_errors} }, "cannot verify $scheme");                  next; diff --git a/perl/Wallet/Schema.pm b/perl/Wallet/Schema.pm index 532c61e..2aac445 100644 --- a/perl/Wallet/Schema.pm +++ b/perl/Wallet/Schema.pm @@ -24,7 +24,7 @@ use DBI;  $VERSION = '0.02';  ############################################################################## -# Implementation +# Data manipulation  ##############################################################################  # Create a new Wallet::Schema object, parse the SQL out of the documentation, @@ -63,6 +63,10 @@ sub sql {      return @{ $self->{sql} };  } +############################################################################## +# Initialization and cleanup +############################################################################## +  # Given a database handle, try to create our database by running the SQL.  Do  # this in a transaction regardless of the database settings and throw an  # exception if this fails.  We have to do a bit of fiddling to get syntax that @@ -116,6 +120,44 @@ sub drop {  }  ############################################################################## +# Administrative actions +############################################################################## + +# Given a database handle, object type, and class name, add a new class +# mapping to that database for the given object type.  This is used to +# register new object types.  Throws an exception on failure. +sub register_object { +    my ($self, $dbh, $type, $class) = @_; +    eval { +        $dbh->begin_work if $dbh->{AutoCommit}; +        my $sql = 'insert into types (ty_name, ty_class) values (?, ?)'; +        $dbh->do ($sql, undef, $type, $class); +        $dbh->commit; +    }; +    if ($@) { +        $dbh->rollback; +        die "$@\n"; +    } +} + +# Given a database handle, ACL verifier scheme, and class name, add a new +# class mapping to that database for the given ACL verifier scheme.  This is +# used to register new ACL schemes.  Throws an exception on failure. +sub register_verifier { +    my ($self, $dbh, $scheme, $class) = @_; +    eval { +        $dbh->begin_work if $dbh->{AutoCommit}; +        my $sql = 'insert into acl_schemes (as_name, as_class) values (?, ?)'; +        $dbh->do ($sql, undef, $scheme, $class); +        $dbh->commit; +    }; +    if ($@) { +        $dbh->rollback; +        die "$@\n"; +    } +} + +##############################################################################  # Schema  ############################################################################## @@ -173,6 +215,24 @@ that are part of the current schema or one of the previous known schema and  won't remove other tables.  On any error, this method will throw a database  exception. +=item register_object (DBH, TYPE, CLASS) + +Given a connected database handle, register in that database a mapping from +the object type TYPE to the class CLASS.  On any error, including attempting +to add a mapping for a type that already exists, this method will throw a +database exception. + +This method will eventually move to another class. + +=item register_verifier (DBH, SCHEME, CLASS) + +Given a connected database handle, register in that database a mapping from +the ACL scheme SCHEME to the class CLASS.  On any error, including +attempting to add a mapping for a scheme that already exists, this method +will throw a database exception. + +This method will eventually move to another class. +  =item sql()  Returns the schema and the population of the normalization tables as a list diff --git a/perl/Wallet/Server.pm b/perl/Wallet/Server.pm index e1655ff..1e86057 100644 --- a/perl/Wallet/Server.pm +++ b/perl/Wallet/Server.pm @@ -24,14 +24,7 @@ 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.02'; - -# This is a mapping of object types to class names, used to determine which -# object implementation should be instantiated for a given object type. -# Currently, there's no dynamic way to recognize new object types, so if you -# extend the wallet system to add new object types, you need to modify this -# list. -%MAPPING = (keytab => 'Wallet::Object::Keytab'); +$VERSION = '0.03';  ##############################################################################  # Utility methods @@ -145,6 +138,24 @@ sub DESTROY {  # Object methods  ############################################################################## +# Given an object type, return the mapping to a class by querying the +# database, or undef if no mapping exists. +sub type_mapping { +    my ($self, $type) = @_; +    my $class; +    eval { +        my $sql = 'select ty_class from types where ty_name = ?'; +        ($class) = $self->{dbh}->selectrow_array ($sql, undef, $type); +        $self->{dbh}->commit; +    }; +    if ($@) { +        $self->error ($@); +        $self->{dbh}->rollback; +        return; +    } +    return $class; +} +  # Given an object which doesn't currently exist, check whether a default_owner  # function is defined and, if so, if it returns an ACL for that object.  If  # so, create the ACL and check if the current user is authorized by that ACL. @@ -214,11 +225,11 @@ sub create_check {  # sets the internal error.  sub create {      my ($self, $type, $name) = @_; -    unless ($MAPPING{$type}) { +    my $class = $self->type_mapping ($type); +    unless ($class) {          $self->error ("unknown object type $type");          return undef;      } -    my $class = $MAPPING{$type};      my $dbh = $self->{dbh};      my $user = $self->{user};      my $host = $self->{host}; @@ -244,11 +255,11 @@ sub create {  # or returns undef and sets the internal error.  sub retrieve {      my ($self, $type, $name) = @_; -    unless ($MAPPING{$type}) { +    my $class = $self->type_mapping ($type); +    unless ($class) {          $self->error ("unknown object type $type");          return undef;      } -    my $class = $MAPPING{$type};      my $object = eval { $class->new ($type, $name, $self->{dbh}) };      if ($@) {          $self->error ($@); diff --git a/perl/t/schema.t b/perl/t/schema.t index 1068048..70378de 100755 --- a/perl/t/schema.t +++ b/perl/t/schema.t @@ -21,7 +21,7 @@ ok (defined $schema, 'Wallet::Schema creation');  ok ($schema->isa ('Wallet::Schema'), ' and class verification');  my @sql = $schema->sql;  ok (@sql > 0, 'sql() returns something'); -is (scalar (@sql), 26, ' and returns the right number of statements'); +is (scalar (@sql), 28, ' and returns the right number of statements');  # Connect to a database and test create.  db_setup; diff --git a/perl/t/server.t b/perl/t/server.t index 229d58d..a1467d1 100755 --- a/perl/t/server.t +++ b/perl/t/server.t @@ -12,14 +12,12 @@ use Test::More tests => 321;  use POSIX qw(strftime);  use Wallet::Config; +use Wallet::Schema;  use Wallet::Server;  use lib 't/lib';  use Util; -# Allow creation of base objects for testing purposes. -$Wallet::Server::MAPPING{base} = 'Wallet::Object::Base'; -  # Some global defaults to use.  my $admin = 'admin@EXAMPLE.COM';  my $user1 = 'alice@EXAMPLE.COM'; @@ -40,6 +38,10 @@ ok ($server->isa ('Wallet::Server'), ' and returned the right class');  my $dbh = $server->dbh;  ok (defined ($dbh), ' and returns a defined database handle'); +# Allow creation of base objects for testing purposes. +my $schema = Wallet::Schema->new; +$schema->register_object ($dbh, 'base', 'Wallet::Object::Base'); +  # 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. @@ -867,7 +869,7 @@ is ($server->error, "$user2 not authorized to create base:service/foo",      ' with the right error');  # Clean up. -my $schema = Wallet::Schema->new; +$schema = Wallet::Schema->new;  $schema->drop ($server->dbh);  unlink 'wallet-db'; | 
