diff options
author | Russ Allbery <rra@stanford.edu> | 2007-08-29 16:39:35 +0000 |
---|---|---|
committer | Russ Allbery <rra@stanford.edu> | 2007-08-29 16:39:35 +0000 |
commit | 9d0b4df45a4be981b8d23e9cd37e70298e3dec59 (patch) | |
tree | 3c95fe708827007e6e24342480018668003af333 | |
parent | d7225438a415d76fb08b2e15cbb581be94e3f69f (diff) |
Convert the schema documentation into a Perl class that contains the same
information but can also return the SQL commands or apply them to a
database.
-rw-r--r-- | docs/design-schema | 156 | ||||
-rw-r--r-- | perl/Wallet/Schema.pm | 343 |
2 files changed, 343 insertions, 156 deletions
diff --git a/docs/design-schema b/docs/design-schema deleted file mode 100644 index 8e04f49..0000000 --- a/docs/design-schema +++ /dev/null @@ -1,156 +0,0 @@ - Database Schema for the Wallet - -Introduction - - Here should be a comprehensive list of the tables used by the wallet, - the SQL to create those tables, and a specification of what they're - for. It's possible that this file will later be written in some other - format to make extraction of the SQL easier. Please do not copy this - data into some other file that could get out of sync with this - documentation; instead, if it's necessary to change the format, please - move this file elsewhere and keep the documentation with the schema. - -Object Metadata - - Each object stored in the wallet is represented by an entry in the - objects table: - - create table objects - (ob_name varchar(255) not null, - ob_type varchar(16) - not null references types(ty_name), - ob_owner integer default null references acls(ac_id), - ob_acl_get integer default null references acls(ac_id), - ob_acl_store integer default null references acls(ac_id), - ob_acl_show integer default null references acls(ac_id), - ob_acl_destroy integer default null references acls(ac_id), - ob_acl_flags integer default null references acls(ac_id), - ob_expires datetime default 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) default null, - ob_stored_from varchar(255) default null, - ob_stored_on datetime default null, - ob_downloaded_by varchar(255) default null, - ob_downloaded_from varchar(255) default null, - ob_downloaded_on datetime default null, - primary key (ob_name, ob_type), - index (ob_owner), - index (ob_expires)); - - Object names are not globally unique but only unique within their - type, so the table has a joint primary key. I haven't yet decided - what indices the table will need. - - Each object has an owner and then up to five more specific ACLs. The - ob_acl_flags ACL controls who can set flags on this object. Each ACL - references entries in the following table: - - create table acls - (ac_id integer auto_increment primary key, - ac_name varchar(255) not null, - unique index (ac_name)); - - This just keeps track of unique ACL identifiers. The data is then - stored in: - - create table acl_entries - (ae_id integer - not null references acls(ac_id), - ae_scheme varchar(32) - not null references acl_schemes(as_name), - ae_identifier varchar(255) - not null); - - Each object may have zero or more flags associated with it. - - create table flags - (fl_object varchar(255) - not null references objects(ob_name), - fl_type varchar(16) - not null references objects(ob_type), - fl_flag varchar(32) - not null references flag_names(fn_name)); - - Every change made to any object in the wallet database will be - recorded in this table. - - create table object_history - (oh_id integer auto_increment primary key, - oh_object varchar(255) - not null references objects(ob_object), - oh_type varchar(16) - not null references objects(ob_type), - oh_action - enum('create', 'destroy', 'get', 'store', set') not null, - oh_field - enum('owner', 'acl_get', 'acl_store', 'acl_show', - 'acl_destroy', 'acl_flags', 'expires', 'flags', - 'type_data'), - oh_type_field varchar(255), - oh_from varchar(255), - oh_to varchar(255), - oh_by varchar(255) not null, - oh_from varchar(255) not hull, - oh_on datetime not null, - index (oh_object, oh_type)); - - For a change of type create, get, store, or destroy, only the action - and the trace records (by, from, and on) are stored. For changes to - columns or to the flags table, oh_field takes what attribute is - changed, oh_from takes the previous value converted to a string and - oh_to takes the next value similarly converted to a string. The - special field value "type_data" is used when type-specific data is - changed, and in that case (and only that case) some type-specific name - for the data being changed is stored in oh_type_field. - - Every change made to any ACL in the database will be recorded in this - table. - - create table acl_history - (ah_id integer auto_increment primary key, - ah_acl integer not null, - ah_action enum('create', 'destroy', 'add', 'remove') - 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, - index (ah_acl)); - - For a change of type create or destroy, only the action and the trace - records (by, from, and on) are stored. For a change to the lines of - an ACL, the scheme and identifier of the line that was added or - removed is included. Note that changes to the ACL name are not - recorded; ACLs are always tracked by system-generated ID, so name - changes are purely cosmetic. - - The following are normalization tables used to constrain the values - - create table types - (ty_name varchar(16) primary key); - - create table acl_schemes - (as_name varchar(32) primary key); - - create table flag_names - (fn_name varchar(32) primary key); - -Storage Backend Data - - To support restricting the allowable enctypes for a given keytab, the - keytab backend will use the following table: - - create table keytab_enctypes - (ke_principal varchar(255) - not null references objects(ob_name), - ke_enctype varchar(255) - not null references enctypes(en_name)); - - There is a normalization table to ensure that only supported enctypes - are configured: - - create table enctypes - (en_name varchar(255) primary key); diff --git a/perl/Wallet/Schema.pm b/perl/Wallet/Schema.pm new file mode 100644 index 0000000..0e148dd --- /dev/null +++ b/perl/Wallet/Schema.pm @@ -0,0 +1,343 @@ +# Wallet::Schema -- Database schema for the wallet system. +# $Id$ +# +# Written by Russ Allbery <rra@stanford.edu> +# Copyright 2007 Board of Trustees, Leland Stanford Jr. University +# +# See README for licensing terms. + +############################################################################## +# Modules and declarations +############################################################################## + +package Wallet::Config; +require 5.006; + +use strict; +use vars qw(@TABLES $VERSION); + +use DBI; + +# 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'; + +############################################################################## +# Implementation +############################################################################## + +# Create a new Wallet::Schema object, parse the SQL out of the documentation, +# and store it in the object. +sub new { + my ($class) = @_; + local $_; + my ($found, @sql); + $command = ''; + while (<DATA>) { + if (not $found and /^=head1 SCHEMA/) { + $found = 1; + } elsif ($found and /^=head1 /) { + last; + } elsif ($found and /^ /) { + s/^ //; + $command .= $_; + if (/;$/) { + push (@sql, $command); + $command = ''; + } + } + } + close DATA; + my $self = { sql => [ @sql ] }; + bless ($self, $class); + return $self; +} + +# Returns the SQL as a list of commands. +sub sql { + my ($self) = @_; + return @{ $self->{sql} }; +} + +# 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. +sub create { + my ($self, $dbh) = @_; + eval { + $dbh->begin_work; + for my $sql (@{ $self->{sql} }) { + $dbh->do ($sql, { RaiseError => 1 }); + } + $dbh->commit; + }; + if ($@) { + $dbh->rollback; + die "$@\n"; + } +} + +############################################################################## +# Schema +############################################################################## + +# The following POD is also parsed by the code to extract SQL blocks. Don't +# add any verbatim blocks to this documentation in the SCHEMA section that +# aren't intended to be SQL. + +1; +__DATA__ + +=head1 NAME + +Wallet::Schema - Database schema for the wallet system + +=head1 SYNOPSIS + + use Wallet::Schema; + my $schema = Wallet::Schema->new; + my @sql = $schema->sql; + $schema->create ($dbh); + +=head1 DESCRIPTION + +This class encapsulates the database schema for the wallet system. The +documentation you're reading explains and comments the schema. The Perl +object extracts the schema from the documentation and can either return it +as a list of SQL commands to run or run those commands given a connected +database handle. + +This schema attempts to be portable SQL, but it is designed for use with +MySQL and may require some modifications for other databases. + +=head1 METHODS + +=over 4 + +=item new() + +Instantiates a new Wallet::Schema object. This parses the documentation and +extracts the schema, but otherwise doesn't do anything. + +=item create(DBH) + +Given a connected database handle, runs the SQL commands necessary to create +the wallet database in an otherwise empty database. This method will not +drop any existing tables and will therefore fail if a wallet database has +already been created. On any error, this method will throw a database +exception. + +=item sql() + +Returns the schema and the population of the normalization tables as a list +of SQL commands to run to create the wallet database in an otherwise empty +database. + +=back + +=head1 SCHEMA + +=head2 Normalization Tables + +The following are normalization tables used to constrain the values in other +tables. + +Holds the supported flag names: + + create table flag_names + (fn_name varchar(32) primary key); + insert into flag_names (fn_name) values ('locked'); + insert into flag_names (fn_name) values ('unchanging'); + +Holds the supported object types and their corresponding Perl classes: + + create table types + (ty_name varchar(16) primary key, + ty_class varchar(64)); + insert into types (ty_name, ty_class) + values ('keytab', 'Wallet::Object::Keytab'); + +Holds the supported ACL schemes and their corresponding Perl classes: + + create table acl_schemes + (as_name varchar(32) primary key, + as_class varchar(64)); + insert into acl_schemes (as_name, as_class) + values ('krb5', 'Wallet::ACL::Krb5'); + +If you have extended the wallet to support additional object types or +additional ACL schemes, you will want to add additional rows to these tables +mapping those types or schemes to Perl classes that implement the object or +ACL verifier APIs. + +=head2 ACL Tables + +A wallet ACL consists of zero or more ACL entries, each of which is a scheme +and an identifier. The scheme identifies the check that should be performed +and the identifier is additional scheme-specific information. Each ACL +references entries in the following table: + + create table acls + (ac_id integer auto_increment primary key, + ac_name varchar(255) not null, + unique index (ac_name)); + +This just keeps track of unique ACL identifiers. The data is then stored +in: + + create table acl_entries + (ae_id integer not null references acls(ac_id), + ae_scheme varchar(32) + not null references acl_schemes(as_name), + ae_identifier varchar(255) not null, + index (ae_id)); + +ACLs may be referred to in the API via either the numeric ID or the +human-readable name, but internally ACLs are always referenced by numeric ID +so that they can be renamed without requiring complex data modifications. + +Currently, the ACL named C<ADMIN> (case-sensitive) is special-cased in the +Wallet::Server code and granted global access. + +Every change made to any ACL in the database will be recorded in this +table. + + create table acl_history + (ah_id integer auto_increment primary key, + ah_acl integer not null, + ah_action enum('create', 'destroy', 'add', 'remove') + 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, + index (ah_acl)); + +For a change of type create or destroy, only the action and the trace +records (by, from, and on) are stored. For a change to the lines of an ACL, +the scheme and identifier of the line that was added or removed is included. +Note that changes to the ACL name are not recorded; ACLs are always tracked +by system-generated ID, so name changes are purely cosmetic. + +ah_by stores the authenticated identity that made the change, ah_from stores +the host from which they made the change, and ah_on stores the time the +change was made. + +=head2 Object Tables + +Each object stored in the wallet is represented by an entry in the objects +table: + + create table objects + (ob_name varchar(255) not null, + ob_type varchar(16) + not null references types(ty_name), + ob_owner integer default null references acls(ac_id), + ob_acl_get integer default null references acls(ac_id), + ob_acl_store integer default null references acls(ac_id), + ob_acl_show integer default null references acls(ac_id), + ob_acl_destroy integer default null references acls(ac_id), + ob_acl_flags integer default null references acls(ac_id), + ob_expires datetime default 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) default null, + ob_stored_from varchar(255) default null, + ob_stored_on datetime default null, + ob_downloaded_by varchar(255) default null, + ob_downloaded_from varchar(255) default null, + ob_downloaded_on datetime default null, + primary key (ob_name, ob_type), + index (ob_owner), + index (ob_expires)); + +Object names are not globally unique but only unique within their type, so +the table has a joint primary key. Each object has an owner and then up to +five more specific ACLs. The owner provides permission for get, store, and +show operations if no more specific ACL is set. It does not provide +permission for destroy or flags. + +The ob_acl_flags ACL controls who can set flags on this object. Each object +may have zero or more flags associated with it: + + create table flags + (fl_object varchar(255) + not null references objects(ob_name), + fl_type varchar(16) + not null references objects(ob_type), + fl_flag varchar(32) + not null references flag_names(fn_name), + index (fl_object, fl_type)); + +Every change made to any object in the wallet database will be recorded in +this table: + + create table object_history + (oh_id integer auto_increment primary key, + oh_object varchar(255) + not null references objects(ob_object), + oh_type varchar(16) + not null references objects(ob_type), + oh_action + enum('create', 'destroy', 'get', 'store', set') not null, + oh_field + enum('owner', 'acl_get', 'acl_store', 'acl_show', + 'acl_destroy', 'acl_flags', 'expires', 'flags', + 'type_data'), + oh_type_field varchar(255), + oh_from varchar(255), + oh_to varchar(255), + oh_by varchar(255) not null, + oh_from varchar(255) not hull, + oh_on datetime not null, + index (oh_object, oh_type)); + +For a change of type create, get, store, or destroy, only the action and the +trace records (by, from, and on) are stored. For changes to columns or to +the flags table, oh_field takes what attribute is changed, oh_from takes the +previous value converted to a string and oh_to takes the next value +similarly converted to a string. The special field value "type_data" is +used when type-specific data is changed, and in that case (and only that +case) some type-specific name for the data being changed is stored in +oh_type_field. + +oh_by stores the authenticated identity that made the change, oh_from stores +the host from which they made the change, and oh_on stores the time the +change was made. + +=head2 Storage Backend Data + +The keytab backend supports restricting the allowable enctypes for a given +keytab. The permitted enctypes are listed in a normalization table: + + create table enctypes + (en_name varchar(255) primary key); + +and then the restrictions for a given keytab are stored in this table: + + create table keytab_enctypes + (ke_principal varchar(255) + not null references objects(ob_name), + ke_enctype varchar(255) + not null references enctypes(en_name), + index (ke_principal)); + +To use this functionality, you will need to populate the enctypes table with +the enctypes that a keytab may be restricted to. Currently, there is no +automated mechanism to do this. + +=head1 SEE ALSO + +wallet-backend(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 |