summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Allbery <rra@stanford.edu>2007-08-29 16:39:35 +0000
committerRuss Allbery <rra@stanford.edu>2007-08-29 16:39:35 +0000
commit9d0b4df45a4be981b8d23e9cd37e70298e3dec59 (patch)
tree3c95fe708827007e6e24342480018668003af333
parentd7225438a415d76fb08b2e15cbb581be94e3f69f (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-schema156
-rw-r--r--perl/Wallet/Schema.pm343
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