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"); | 
