diff options
-rw-r--r-- | TODO | 8 | ||||
-rw-r--r-- | client/wallet.pod | 29 | ||||
-rwxr-xr-x | server/wallet-backend | 85 | ||||
-rw-r--r-- | tests/server/backend-t.in | 66 |
4 files changed, 135 insertions, 53 deletions
@@ -2,14 +2,12 @@ Required to replace leland_srvtab: -* Add arbitrary attribute setting and retrieval to objects and include the - attributes in the object show display. - * Add support for limiting the enctypes of created keytabs by setting the - enctype attribute on the object. + enctype attribute on the object and include the enctypes in the object + show display. * Add an attribute indicating that the principal should be synchronized - with Kerberos v4. + with Kerberos v4 and include it in the object show display. * Implement creation of srvtabs from keytabs in the wallet client. diff --git a/client/wallet.pod b/client/wallet.pod index 263e623..3f7c60b 100644 --- a/client/wallet.pod +++ b/client/wallet.pod @@ -102,10 +102,12 @@ options and commands are ignored. As mentioned above, most commands are only available to wallet administrators. The exceptions are C<get>, C<store>, C<show>, C<destroy>, -C<flag clear>, and C<flag set>. All of those commands have their own -ACLs, and if the appropriate ACL is set, it alone is checked to see if the -user has access. Otherwise, C<get>, C<store>, and C<show> access is -permitted if the user is authorized by the owner ACL of the object. +C<flag clear>, C<flag set>, C<getattr>, and C<setattr>. All of those +commands have their own ACLs except C<getattr>, which uses the C<show> +ACL, and C<setattr>, which uses the C<show> ACL. If the appropriate ACL +is set, it alone is checked to see if the user has access. Otherwise, +C<get>, C<store>, C<show>, C<getattr>, and C<setattr> access is permitted +if the user is authorized by the owner ACL of the object. Administrators can run any command on any object or ACL except for C<get> and C<store>. For C<get> and C<show>, they must still be authorized by @@ -205,6 +207,15 @@ if the C<get>, C<store>, or C<show> ACLs aren't set, authorization falls back to checking the owner ACL. See the C<owner> command for displaying or setting it. +=item getattr <type> <name> <attr> + +Prints the object attribute <attr> for the object identified by <type> and +<name>. Attributes are used to store backend-specific information for a +particular object type, and <attr> must be an attribute type known to the +underlying object implementation. The attribute values, if any, are +printed one per line. If the attribute is not set on this object, nothing +is printed. + =item owner <type> <name> [<owner>] If <owner> is not given, displays the current owner ACL of the object @@ -221,6 +232,16 @@ Sets the ACL <acl>, which must be one of C<get>, C<store>, C<show>, C<destroy>, or C<flags>, to <id> on the object identified by <type> and <name>. If <id> is the empty string, clears that ACL on the object. +=item setattr <type> <name> <attr> <value> [<value> ...] + +Sets the object attribute <attr> for the object identified by <type> and +<name>. Attributes are used to store backend-specific information for a +particular object type, and <attr> must be an attribute type known to the +underlying object implementation. To clear the attribute for this object, +pass in a <value> of the empty string (C<''>). + +Currently, no object attributes are implemented. + =item show <type> <name> Displays the current object metadata for the object identified by <type> diff --git a/server/wallet-backend b/server/wallet-backend index b54f6c3..2ab3daf 100755 --- a/server/wallet-backend +++ b/server/wallet-backend @@ -23,16 +23,16 @@ use Wallet::Server; # Check all arguments against a very restricted set of allowed characters and # to ensure the right number of arguments are taken. The arguments are the -# number of arguments expected, a reference to an array of which argument -# numbers shouldn't be checked, and then the arguments. +# number of arguments expected (minimum and maximum), a reference to an array +# of which argument numbers shouldn't be checked, and then the arguments. # # This function is probably temporary and will be replaced with something that # knows more about the syntax of each command and can check more things. sub check_args { - my ($count, $exclude, @args) = @_; - if (@args < $count) { + my ($min, $max, $exclude, @args) = @_; + if (@args < $min) { die "insufficient arguments\n"; - } elsif (@args > $count) { + } elsif (@args > $max and $max != -1) { die "too many arguments\n"; } my %exclude = map { $_ => 1 } @$exclude; @@ -63,22 +63,22 @@ sub command { if ($command eq 'acl') { my $action = shift @args; if ($action eq 'add') { - check_args (3, [], @args); + check_args (3, 3, [], @args); $server->acl_add (@args) or die $server->error; } elsif ($action eq 'create') { - check_args (1, [], @args); + check_args (1, 1, [], @args); $server->acl_create (@args) or die $server->error; } elsif ($action eq 'destroy') { - check_args (1, [], @args); + check_args (1, 1, [], @args); $server->acl_destroy (@args) or die $server->error; } elsif ($action eq 'remove') { - check_args (3, [], @args); + check_args (3, 3, [], @args); $server->acl_remove (@args) or die $server->error; } elsif ($action eq 'rename') { - check_args (2, [], @args); + check_args (2, 2, [], @args); $server->acl_rename (@args) or die $server->error; } elsif ($action eq 'show') { - check_args (1, [], @args); + check_args (1, 1, [], @args); my $output = $server->acl_show (@args); if (defined $output) { print $output; @@ -89,17 +89,16 @@ sub command { die "unknown command acl $action\n"; } } elsif ($command eq 'create') { - check_args (2, [], @args); + check_args (2, 2, [], @args); $server->create (@args) or die $server->error; } elsif ($command eq 'destroy') { - check_args (2, [], @args); + check_args (2, 2, [], @args); $server->destroy (@args) or die $server->error; } elsif ($command eq 'expires') { + check_args (2, 3, [], @args); if (@args > 2) { - check_args (3, [], @args); $server->expires (@args) or die $server->error; } else { - check_args (2, [], @args); my $output = $server->expires (@args); if (defined $output) { print $output, "\n"; @@ -111,17 +110,16 @@ sub command { } } elsif ($command eq 'flag') { my $action = shift @args; + check_args (3, 3, [], @args); if ($action eq 'clear') { - check_args (3, [], @args); $server->flag_clear (@args) or die $server->error; } elsif ($action eq 'set') { - check_args (3, [], @args); $server->flag_set (@args) or die $server->error; } else { die "unknown command flag $action\n"; } } elsif ($command eq 'get') { - check_args (2, [], @args); + check_args (2, 2, [], @args); my $output = $server->get (@args); if (defined $output) { print $output; @@ -129,7 +127,7 @@ sub command { die $server->error; } } elsif ($command eq 'getacl') { - check_args (3, [], @args); + check_args (3, 3, [], @args); my $output = $server->acl (@args); if (defined $output) { print $output, "\n"; @@ -138,12 +136,19 @@ sub command { } else { die $server->error; } + } elsif ($command eq 'getattr') { + check_args (3, 3, [], @args); + my @result = $server->attr (@args); + if (not @result and $server->error) { + die $server->error; + } elsif (@result) { + print join ("\n", @result, ''); + } } elsif ($command eq 'owner') { + check_args (2, 3, [], @args); if (@args > 2) { - check_args (3, [], @args); $server->owner (@args) or die $server->error; } else { - check_args (2, [], @args); my $output = $server->owner (@args); if (defined $output) { print $output, "\n"; @@ -154,10 +159,13 @@ sub command { } } } elsif ($command eq 'setacl') { - check_args (4, [], @args); + check_args (4, 4, [], @args); $server->acl (@args) or die $server->error; + } elsif ($command eq 'setattr') { + check_args (4, -1, [], @args); + $server->attr (@args) or die $server->error; } elsif ($command eq 'show') { - check_args (2, [], @args); + check_args (2, 2, [], @args); my $output = $server->show (@args); if (defined $output) { print $output; @@ -165,7 +173,7 @@ sub command { die $server->error; } } elsif ($command eq 'store') { - check_args (3, [3], @args); + check_args (3, 3, [3], @args); $server->store (@args) or die $server->error; } else { die "unknown command $command\n"; @@ -214,10 +222,12 @@ B<wallet-backend> takes no traditional options. Most commands are only available to wallet administrators (users on the C<ADMIN> ACL). The exceptions are C<get>, C<store>, C<show>, C<destroy>, -C<flag clear>, and C<flag set>. All of those commands have their own ACLs, -and if the appropriate ACL is set, it alone is checked to see if the user -has access. Otherwise, C<get>, C<store>, and C<show> access is permitted if -the user is authorized by the owner ACL of the object. +C<flag clear>, C<flag set>, C<getattr>, and C<setattr>. All of those +commands have their own ACLs except C<getattr>, which uses the C<show> ACL, +and C<setattr>, which uses the C<show> ACL. If the appropriate ACL is set, +it alone is checked to see if the user has access. Otherwise, C<get>, +C<store>, C<show>, C<getattr>, and C<setattr> access is permitted if the +user is authorized by the owner ACL of the object. Administrators can run any command on any object or ACL except for C<get> and C<store>. For C<get> and C<show>, they must still be authorized by @@ -316,6 +326,15 @@ if the C<get>, C<store>, or C<show> ACLs aren't set, authorization falls back to checking the owner ACL. See the C<owner> command for displaying or setting it. +=item getattr <type> <name> <attr> + +Prints the object attribute <attr> for the object identified by <type> and +<name>. Attributes are used to store backend-specific information for a +particular object type, and <attr> must be an attribute type known to the +underlying object implementation. The attribute values, if any, are printed +one per line. If the attribute is not set on this object, nothing is +printed. + =item owner <type> <name> [<owner>] If <owner> is not given, displays the current owner ACL of the object @@ -332,6 +351,16 @@ Sets the ACL <acl>, which must be one of C<get>, C<store>, C<show>, C<destroy>, or C<flags>, to <id> on the object identified by <type> and <name>. If <id> is the empty string, clears that ACL on the object. +=item setattr <type> <name> <attr> <value> [<value> ...] + +Sets the object attribute <attr> for the object identified by <type> and +<name>. Attributes are used to store backend-specific information for a +particular object type, and <attr> must be an attribute type known to the +underlying object implementation. To clear the attribute for this object, +pass in a <value> of the empty string (C<''>). + +Currently, no object attributes are implemented. + =item show <type> <name> Displays the current object metadata for the object identified by <type> diff --git a/tests/server/backend-t.in b/tests/server/backend-t.in index bac2105..c844d5e 100644 --- a/tests/server/backend-t.in +++ b/tests/server/backend-t.in @@ -5,7 +5,7 @@ use strict; use IO::String; -use Test::More tests => 750; +use Test::More tests => 790; # Create a dummy class for Wallet::Server that prints what method was called # with its arguments and returns data for testing. @@ -66,6 +66,21 @@ sub acl { } } +sub attr { + shift; + print "attr @_\n"; + if ($_[0] eq 'error') { + return; + } elsif ($_[1] eq 'empty') { + $okay = 1; + return; + } elsif (@_ == 3) { + return ('attr1', 'attr2'); + } else { + return 'attr'; + } +} + sub expires { shift; print "expires @_\n"; @@ -144,7 +159,7 @@ is ($out, "$new\n", ' and nothing ran'); ($out, $err) = run_backend ('acl', 'foo'); is ($err, "unknown command acl foo\n", 'Unknown ACL command'); is ($out, "$new\n", ' and nothing ran'); -($out, $err) = run_backend ('flag', 'foo'); +($out, $err) = run_backend ('flag', 'foo', 'service', 'foo', 'foo'); is ($err, "unknown command flag foo\n", 'Unknown flag command'); is ($out, "$new\n", ' and nothing ran'); @@ -154,8 +169,10 @@ my %commands = (create => [2, 2], expires => [2, 3], get => [2, 2], getacl => [3, 3], + getattr => [3, 3], owner => [2, 3], setacl => [4, 4], + setattr => [4, 9], show => [2, 2], store => [3, 3]); my %acl_commands = (add => [3, 3], @@ -171,9 +188,11 @@ for my $command (sort keys %commands) { ($out, $err) = run_backend ($command, ('foo') x ($min - 1)); is ($err, "insufficient arguments\n", "Too few arguments for $command"); is ($out, "$new\n", ' and nothing ran'); - ($out, $err) = run_backend ($command, ('foo') x ($max + 1)); - is ($err, "too many arguments\n", "Too many arguments for $command"); - is ($out, "$new\n", ' and nothing ran'); + unless ($max >= 9) { + ($out, $err) = run_backend ($command, ('foo') x ($max + 1)); + is ($err, "too many arguments\n", "Too many arguments for $command"); + is ($out, "$new\n", ' and nothing ran'); + } my @base = ('foobar') x $max; for my $arg (0 .. ($max - 1)) { my @args = @base; @@ -231,8 +250,9 @@ for my $command (sort keys %flag_commands) { # Now, test that we ran the right functions and passed the correct arguments. my $error = 1; -for my $command (qw/create destroy setacl store/) { - my $method = ($command eq 'setacl') ? 'acl' : $command; +for my $command (qw/create destroy setacl setattr store/) { + my $method = { setacl => 'acl', setattr => 'attr' }->{$command}; + $method ||= $command; my @extra = ('foo') x ($commands{$command}[0] - 2); my $extra = @extra ? join (' ', '', @extra) : ''; ($out, $err) = run_backend ($command, 'type', 'name', @extra); @@ -245,22 +265,30 @@ for my $command (qw/create destroy setacl store/) { ' and ran the right method'); $error++; } -for my $command (qw/expires get getacl owner show/) { - my $method = ($command eq 'getacl') ? 'acl' : $command; +for my $command (qw/expires get getacl getattr owner show/) { + my $method = { getacl => 'acl', getattr => 'attr' }->{$command}; + $method ||= $command; my @extra = ('foo') x ($commands{$command}[0] - 2); my $extra = @extra ? join (' ', '', @extra) : ''; - my $newline = ($command eq 'get' or $command eq 'show') ? '' : "\n"; - ($out, $err) = run_backend ($command, 'type', 'name', @extra); - is ($err, '', "Command $command ran with no errors"); - is ($out, "$new\n$method type name$extra\n$method$newline", - ' and ran the right method with output'); - if ($command ne 'get' and $command ne 'getacl' and $command ne 'show') { + if ($command eq 'getattr') { + ($out, $err) = run_backend ($command, 'type', 'name', @extra); + is ($err, '', "Command $command ran with no errors"); + is ($out, "$new\n$method type name$extra\nattr1\nattr2\n", + ' and ran the right method with output'); + } else { + my $newline = ($command eq 'get' or $command eq 'show') ? '' : "\n"; + ($out, $err) = run_backend ($command, 'type', 'name', @extra); + is ($err, '', "Command $command ran with no errors"); + is ($out, "$new\n$method type name$extra\n$method$newline", + ' and ran the right method with output'); + } + if ($command eq 'expires' or $command eq 'owner') { ($out, $err) = run_backend ($command, 'type', 'name', @extra, 'foo'); is ($err, '', "Command $command ran with no errors (setting)"); is ($out, "$new\n$method type name$extra foo\n", ' and ran the right method'); } - if ($command ne 'get' and $command ne 'show') { + if ($command eq 'expires' or $command eq 'getacl' or $command eq 'owner') { ($out, $err) = run_backend ($command, 'type', 'empty', @extra); is ($err, '', "Command $command ran with no errors (empty)"); my $desc; @@ -270,6 +298,12 @@ for my $command (qw/expires get getacl owner show/) { is ($out, "$new\n$method type empty$extra\nNo $desc set\n", ' and ran the right method with output'); $error++; + } elsif ($command eq 'getattr') { + ($out, $err) = run_backend ($command, 'type', 'empty', @extra); + is ($err, '', "Command $command ran with no errors (empty)"); + is ($out, "$new\n$method type empty$extra\n", + ' and ran the right method with output'); + $error++; } ($out, $err) = run_backend ($command, 'error', 'name', @extra); is ($err, "error count $error\n", "Command $command ran with errors"); |