veyron/tools/principal: Various enhancements.
(1) Introduced the "create" command to initialize a principal with
a customized blessing (as opposed to forcing the "user@host-pid"
string that is automatically generated)
(2) Added a "bless" command to allow one principal to bless another
(3) Invoke AddToRoots in commands that add blessings to the store
(can be disabled with a flag)
(4) Do not require the VEYRON_CREDENTIALS environment variable
for commands like "help" and "dumpblessings", which don't need them.
(5) Update the test script
(6) Separate all store related commands to a sub-command
Change-Id: Ib94539464f90c14d91737717eadbf6d2112cef4c
diff --git a/tools/principal/main.go b/tools/principal/main.go
index a0a61c1..add120f 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -10,54 +10,65 @@
"time"
"veyron.io/veyron/veyron/lib/cmdline"
+ vsecurity "veyron.io/veyron/veyron/security"
"veyron.io/veyron/veyron/services/identity"
"veyron.io/veyron/veyron/services/identity/util"
+ "veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/vdl/vdlutil"
)
+const VEYRON_CREDENTIALS = "VEYRON_CREDENTIALS"
+
var (
// Flags for the "blessself" command
- flagBlessFor time.Duration
- flagAddForPeer string
+ flagBlessSelfFor time.Duration
- // Flags for the "seekblessing" command
- flagSeekBlessingFrom string
- flagSkipSetDefault bool
- flagForPeer string
+ // Flags for the "bless" command
+ flagBlessFor time.Duration
+ flagBlessWith string
+
+ // Flags for the "seekblessings" command
+ flagSeekBlessingsFrom string
+ flagSeekBlessingsSetDefault bool
+ flagSeekBlessingsForPeer string
+
+ // Flags common to many commands
+ flagAddToRoots bool
cmdDump = &cmdline.Command{
Name: "dump",
Short: "Dump out information about the principal",
Long: `
-Dumps out information about the principal specified by the environment
+Prints out information about the principal specified by the environment
(VEYRON_CREDENTIALS) that this tool is running in.
`,
Run: func(cmd *cmdline.Command, args []string) error {
- p := rt.R().Principal()
+ p, err := principal()
+ if err != nil {
+ return err
+ }
fmt.Printf("Public key : %v\n", p.PublicKey())
- fmt.Println("")
fmt.Println("---------------- BlessingStore ----------------")
fmt.Printf("%v", p.BlessingStore().DebugString())
- fmt.Println("")
fmt.Println("---------------- BlessingRoots ----------------")
fmt.Printf("%v", p.Roots().DebugString())
return nil
},
}
- cmdPrint = &cmdline.Command{
- Name: "print",
- Short: "Print out information about the provided blessing",
+ cmdDumpBlessings = &cmdline.Command{
+ Name: "dumpblessings",
+ Short: "Dump out information about the provided blessings",
Long: `
-Prints out information about the blessing (typically obtained from this tool)
+Prints out information about the blessings (typically obtained from this tool)
encoded in the provided file.
`,
ArgsName: "<file>",
ArgsLong: `
-<file> is the path to a file containing a blessing typically obtained from
+<file> is the path to a file containing blessings typically obtained from
this tool. - is used for STDIN.
`,
Run: func(cmd *cmdline.Command, args []string) error {
@@ -68,8 +79,21 @@
if err != nil {
return fmt.Errorf("failed to decode provided blessings: %v", err)
}
- fmt.Printf("Blessings: %v\n", blessings)
- fmt.Printf("PublicKey: %v\n", blessings.PublicKey())
+ wire := security.MarshalBlessings(blessings)
+ fmt.Printf("Blessings : %v\n", blessings)
+ fmt.Printf("PublicKey : %v\n", blessings.PublicKey())
+ fmt.Printf("Certificates : %d chains with (#certificates, #caveats) = ", len(wire.CertificateChains))
+ for idx, chain := range wire.CertificateChains {
+ ncaveats := 0
+ for _, cert := range chain {
+ ncaveats += len(cert.Caveats)
+ }
+ if idx > 0 {
+ fmt.Printf(" + ")
+ }
+ fmt.Printf("(%d, %d)", len(chain), ncaveats)
+ }
+ fmt.Println("")
return nil
},
}
@@ -101,14 +125,18 @@
}
var caveats []security.Caveat
- if flagBlessFor != 0 {
- cav, err := security.ExpiryCaveat(time.Now().Add(flagBlessFor))
+ if flagBlessSelfFor != 0 {
+ cav, err := security.ExpiryCaveat(time.Now().Add(flagBlessSelfFor))
if err != nil {
return fmt.Errorf("failed to create expiration Caveat: %v", err)
}
caveats = append(caveats, cav)
}
- blessing, err := rt.R().Principal().BlessSelf(name, caveats...)
+ p, err := principal()
+ if err != nil {
+ return err
+ }
+ blessing, err := p.BlessSelf(name, caveats...)
if err != nil {
return fmt.Errorf("failed to create self-signed blessing for name %q: %v", name, err)
}
@@ -117,8 +145,75 @@
},
}
- cmdForPeer = &cmdline.Command{
- Name: "store.forpeer",
+ cmdBless = &cmdline.Command{
+ Name: "bless",
+ Short: "Bless another principal",
+ Long: `
+ Returns a set of blessings obtained when one principal blesses another.
+
+ The blesser is obtained from the VEYRON_CREDENTIALS environment variable.
+ The principal to be blessed is specified as either a path to the VEYRON_CREDENTIALS directory of the other principal, or the filename (or - for STDIN) of any other blessing of that principal.
+ The blessing that the blesser uses (i.e., which is extended to create the blessing) is the default one from the blessers store, or specified via the --with flag.
+ The blessing is valid only for the duration specified in --for.
+
+ For example, let's say a principal with the default blessing "alice" wants to bless another principal as "alice/bob", the invocation would be:
+ VEYRON_CREDENTIALS=<path to alice> principal bless <path to bob> friend
+ `,
+ ArgsName: "<principal to bless> <extension>",
+ ArgsLong: `
+ <principal to bless> represents the principal to be blessed (i.e., whose public key will be provided with a name).
+ This can either be a path to a file containing any other set of blessings of that principal (or - for STDIN) or the
+ path to the VEYRON_CREDENTIALS directory of that principal.
+
+ <extension> is the string extension that will be applied to create the blessing.
+ `,
+ Run: func(cmd *cmdline.Command, args []string) error {
+ if len(args) != 2 {
+ return fmt.Errorf("require exactly two arguments, provided %d", len(args))
+ }
+ p, err := principal()
+ if err != nil {
+ return err
+ }
+
+ var with security.Blessings
+ if len(flagBlessWith) > 0 {
+ if with, err = decodeBlessings(flagBlessWith); err != nil {
+ return fmt.Errorf("failed to read blessings from --with=%q: %v", flagBlessWith, err)
+ }
+ } else {
+ with = p.BlessingStore().Default()
+ }
+
+ var key security.PublicKey
+ tobless, extension := args[0], args[1]
+ if finfo, err := os.Stat(tobless); err == nil && finfo.IsDir() {
+ other, _, err := vsecurity.NewPersistentPrincipal(tobless)
+ if err != nil {
+ return fmt.Errorf("failed to read principal in directory %q: %v", tobless, err)
+ }
+ key = other.PublicKey()
+ } else if other, err := decodeBlessings(tobless); err != nil {
+ return fmt.Errorf("failed to decode blessings in %q: %v", tobless, err)
+ } else {
+ key = other.PublicKey()
+ }
+
+ caveat, err := security.ExpiryCaveat(time.Now().Add(flagBlessFor))
+ if err != nil {
+ return fmt.Errorf("failed to create ExpirtyCaveat: %v", err)
+ }
+
+ blessings, err := p.Bless(key, with, extension, caveat)
+ if err != nil {
+ return fmt.Errorf("Bless(%v, %v, %q, ExpiryCaveat(%v)) failed: %v", key, with, extension, flagBlessFor, err)
+ }
+ return dumpBlessings(blessings)
+ },
+ }
+
+ cmdStoreForPeer = &cmdline.Command{
+ Name: "forpeer",
Short: "Return blessings marked for the provided peer",
Long: `
Returns blessings that are marked for the provided peer in the
@@ -134,12 +229,16 @@
blessings set on the store with the "..." pattern).
`,
Run: func(cmd *cmdline.Command, args []string) error {
- return dumpBlessings(rt.R().Principal().BlessingStore().ForPeer(args...))
+ p, err := principal()
+ if err != nil {
+ return err
+ }
+ return dumpBlessings(p.BlessingStore().ForPeer(args...))
},
}
- cmdDefault = &cmdline.Command{
- Name: "store.default",
+ cmdStoreDefault = &cmdline.Command{
+ Name: "default",
Short: "Return blessings marked as default",
Long: `
Returns blessings that are marked as default in the BlessingStore
@@ -147,12 +246,16 @@
is running in.
`,
Run: func(cmd *cmdline.Command, args []string) error {
- return dumpBlessings(rt.R().Principal().BlessingStore().Default())
+ p, err := principal()
+ if err != nil {
+ return err
+ }
+ return dumpBlessings(p.BlessingStore().Default())
},
}
- cmdSet = &cmdline.Command{
- Name: "store.set",
+ cmdStoreSet = &cmdline.Command{
+ Name: "set",
Short: "Set provided blessings for peer",
Long: `
Marks the provided blessings to be shared with the provided
@@ -179,22 +282,31 @@
`,
Run: func(cmd *cmdline.Command, args []string) error {
if len(args) != 2 {
- return fmt.Errorf("requires exactly two arguments <file>, <pattern>, provided %d", cmd.Name, len(args))
+ return fmt.Errorf("requires exactly two arguments <file>, <pattern>, provided %d", len(args))
}
blessings, err := decodeBlessings(args[0])
if err != nil {
return fmt.Errorf("failed to decode provided blessings: %v", err)
}
pattern := security.BlessingPattern(args[1])
- if _, err := rt.R().Principal().BlessingStore().Set(blessings, pattern); err != nil {
+ p, err := principal()
+ if err != nil {
+ return err
+ }
+ if _, err := p.BlessingStore().Set(blessings, pattern); err != nil {
return fmt.Errorf("failed to set blessings %v for peers %v: %v", blessings, pattern, err)
}
+ if flagAddToRoots {
+ if err := p.AddToRoots(blessings); err != nil {
+ return fmt.Errorf("AddToRoots failed: %v", err)
+ }
+ }
return nil
},
}
- cmdSetDefault = &cmdline.Command{
- Name: "store.setdefault",
+ cmdStoreSetDefault = &cmdline.Command{
+ Name: "setdefault",
Short: "Set provided blessings as default",
Long: `
Sets the provided blessings as default in the BlessingStore specified
@@ -210,15 +322,64 @@
`,
Run: func(cmd *cmdline.Command, args []string) error {
if len(args) != 1 {
- return fmt.Errorf("requires exactly one argument, <file>, provided %d", cmd.Name, len(args))
+ return fmt.Errorf("requires exactly one argument, <file>, provided %d", len(args))
}
blessings, err := decodeBlessings(args[0])
if err != nil {
return fmt.Errorf("failed to decode provided blessings: %v", err)
}
- if err := rt.R().Principal().BlessingStore().SetDefault(blessings); err != nil {
+ p, err := principal()
+ if err != nil {
+ return err
+ }
+ if err = p.BlessingStore().SetDefault(blessings); err != nil {
return fmt.Errorf("failed to set blessings %v as default: %v", blessings, err)
}
+ if flagAddToRoots {
+ if err := p.AddToRoots(blessings); err != nil {
+ return fmt.Errorf("AddToRoots failed: %v", err)
+ }
+ }
+ return nil
+ },
+ }
+
+ cmdCreate = &cmdline.Command{
+ Name: "create",
+ Short: "Create a new principal and persist it into a directory",
+ Long: `
+ Creates a new principal with a single self-blessed blessing and writes it out
+ to the provided directory. The same directory can be used to set the VEYRON_CREDENTIALS
+ environment variables for other veyron applications.
+ `,
+ ArgsName: "<directory> <blessing>",
+ ArgsLong: `
+ <directory> is the directory to which the principal will be persisted.
+ <blessing> is the self-blessed blessing that the principal will be setup to use by default.
+ `,
+ Run: func(cmd *cmdline.Command, args []string) error {
+ if len(args) != 2 {
+ return fmt.Errorf("requires exactly two arguments: <directory> and <blessing>, provided %d", len(args))
+ }
+ dir, name := args[0], args[1]
+ p, existed, err := vsecurity.NewPersistentPrincipal(dir)
+ if existed {
+ return fmt.Errorf("principal already exists in %q", dir)
+ }
+ blessings, err := p.BlessSelf(name)
+ if err != nil {
+ return fmt.Errorf("BlessSelf(%q) failed: %v", name, err)
+ }
+ if err := p.BlessingStore().SetDefault(blessings); err != nil {
+ return fmt.Errorf("BlessingStore.SetDefault(%v) failed: %v", blessings, err)
+ }
+ if _, err := p.BlessingStore().Set(blessings, security.AllPrincipals); err != nil {
+ return fmt.Errorf("BlessingStore.Set(%v, %q) failed: %v", blessings, security.AllPrincipals, err)
+ }
+ if err := p.AddToRoots(blessings); err != nil {
+ return fmt.Errorf("AddToRoots(%v) failed: %v", blessings, err)
+ }
+ fmt.Printf("%s=%q\n", VEYRON_CREDENTIALS, dir)
return nil
},
}
@@ -241,14 +402,18 @@
Run: func(cmd *cmdline.Command, args []string) error {
blessedChan := make(chan string)
defer close(blessedChan)
- macaroonChan, err := getMacaroonForBlessRPC(flagSeekBlessingFrom, blessedChan)
+ macaroonChan, err := getMacaroonForBlessRPC(flagSeekBlessingsFrom, blessedChan)
if err != nil {
return fmt.Errorf("failed to get macaroon from Veyron blesser: %v", err)
}
macaroon := <-macaroonChan
service := <-macaroonChan
- ctx, cancel := rt.R().NewContext().WithTimeout(time.Minute)
+ r, err := runtime()
+ if err != nil {
+ return err
+ }
+ ctx, cancel := r.NewContext().WithTimeout(time.Minute)
defer cancel()
var reply vdlutil.Any
@@ -271,14 +436,20 @@
// Wait for getTokenForBlessRPC to clean up:
<-macaroonChan
- if !flagSkipSetDefault {
- if err := rt.R().Principal().BlessingStore().SetDefault(blessings); err != nil {
+ if flagSeekBlessingsSetDefault {
+ if err := r.Principal().BlessingStore().SetDefault(blessings); err != nil {
return fmt.Errorf("failed to set blessings %v as default: %v", blessings, err)
}
}
- pattern := security.BlessingPattern(flagForPeer)
- if _, err := rt.R().Principal().BlessingStore().Set(blessings, pattern); err != nil {
- return fmt.Errorf("failed to set blessings %v for peers %v: %v", blessings, pattern, err)
+ if pattern := security.BlessingPattern(flagSeekBlessingsForPeer); len(pattern) > 0 {
+ if _, err := r.Principal().BlessingStore().Set(blessings, pattern); err != nil {
+ return fmt.Errorf("failed to set blessings %v for peers %v: %v", blessings, pattern, err)
+ }
+ }
+ if flagAddToRoots {
+ if err := r.Principal().AddToRoots(blessings); err != nil {
+ return fmt.Errorf("AddToRoots failed: %v", err)
+ }
}
return dumpBlessings(blessings)
},
@@ -286,16 +457,26 @@
)
func main() {
- if len(os.Getenv("VEYRON_CREDENTIALS")) == 0 {
- // TODO(ataly, ashankar): Handle this case
- fmt.Fprintf(os.Stderr, "ERROR: Please set the VEYRON_CREDENTIALS environment variable\n")
- os.Exit(2)
+ cmdBlessSelf.Flags.DurationVar(&flagBlessSelfFor, "for", 0, "Duration of blessing validity (zero means no that the blessing is always valid)")
+ cmdBless.Flags.DurationVar(&flagBlessFor, "for", time.Minute, "Duration of blessing validity")
+ cmdBless.Flags.StringVar(&flagBlessWith, "with", "", "Path to file containing blessing to extend. ")
+ cmdSeekBlessings.Flags.StringVar(&flagSeekBlessingsFrom, "from", "https://proxy.envyor.com:8125/google", "URL to use to begin the seek blessings process")
+ cmdSeekBlessings.Flags.BoolVar(&flagSeekBlessingsSetDefault, "set_default", true, "If true, the blessings obtained will be set as the default blessing in the store")
+ cmdSeekBlessings.Flags.StringVar(&flagSeekBlessingsForPeer, "for_peer", string(security.AllPrincipals), "If non-empty, the blessings obtained will be marked for peers matching this pattern in the store")
+ cmdSeekBlessings.Flags.BoolVar(&flagAddToRoots, "add_to_roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
+ cmdStoreSet.Flags.BoolVar(&flagAddToRoots, "add_to_roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
+ cmdStoreSetDefault.Flags.BoolVar(&flagAddToRoots, "add_to_roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
+
+ cmdStore := &cmdline.Command{
+ Name: "store",
+ Short: "Manipulate and inspect the principal's blessing store",
+ Long: `
+Commands to manipulate and inspect the blessing store of the principal.
+
+All blessings are printed to stdout using base64-VOM-encoding
+`,
+ Children: []*cmdline.Command{cmdStoreDefault, cmdStoreSetDefault, cmdStoreForPeer, cmdStoreSet},
}
- rt.Init()
- cmdBlessSelf.Flags.DurationVar(&flagBlessFor, "for", 0*time.Hour, "Expiry time of Blessing (optional)")
- cmdSeekBlessings.Flags.StringVar(&flagSeekBlessingFrom, "from", "https://proxy.envyor.com:8125/google", "URL to use to begin the seek blessings process")
- cmdSeekBlessings.Flags.BoolVar(&flagSkipSetDefault, "skip_set_default", false, "flag to indicate that the blessings obtained from the Veyron blesser must not be set as default on the principals's blessing store")
- cmdSeekBlessings.Flags.StringVar(&flagForPeer, "for_peer", "...", "pattern to be used while setting the blessings obtained from the Veyron blesser on the principal's blessing store")
(&cmdline.Command{
Name: "principal",
@@ -306,10 +487,25 @@
All objects are printed using base64-VOM-encoding.
`,
- Children: []*cmdline.Command{cmdDump, cmdPrint, cmdBlessSelf, cmdDefault, cmdForPeer, cmdSetDefault, cmdSet, cmdSeekBlessings},
+ Children: []*cmdline.Command{cmdCreate, cmdSeekBlessings, cmdDump, cmdDumpBlessings, cmdBlessSelf, cmdBless, cmdStore},
}).Main()
}
+func runtime() (veyron2.Runtime, error) {
+ if len(os.Getenv(VEYRON_CREDENTIALS)) == 0 {
+ return nil, fmt.Errorf("VEYRON_CREDENTIALS environment variable must be set")
+ }
+ return rt.Init(), nil
+}
+
+func principal() (security.Principal, error) {
+ r, err := runtime()
+ if err != nil {
+ return nil, err
+ }
+ return r.Principal(), nil
+}
+
func decodeBlessings(fname string) (security.Blessings, error) {
var wire security.WireBlessings
if err := decode(fname, &wire); err != nil {
diff --git a/tools/principal/test.sh b/tools/principal/test.sh
index 86e5fd2..d0a18d0 100755
--- a/tools/principal/test.sh
+++ b/tools/principal/test.sh
@@ -14,85 +14,85 @@
veyron go build veyron.io/veyron/veyron/tools/principal || shell_test::fail "line ${LINENO}: failed to build principal"
}
-extractBlessings() {
- awk '/Blessings/ { st = index($0," "); print substr($0,st+1)}'
+# rmpublickey replaces public keys (16 hex bytes, :-separated) with XX:....
+# This substitution enables comparison with golden output even when keys are freshly
+# minted by the "principal create" command.
+rmpublickey() {
+ sed -e "s/\([0-9a-f]\{2\}:\)\{15\}[0-9a-f]\{2\}/XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX/g"
+}
+
+dumpblessings() {
+ ./principal dumpblessings "$1" | rmpublickey
}
main() {
- local GOT WANT
-
- # Build binaries.
cd "${WORKDIR}"
build
- # Set VEYRON_CREDENTIALS.
- export VEYRON_CREDENTIALS="${WORKDIR}"
+ # Prevent any VEYRON_CREDENTIALS in the environment from interfering with this test.
+ unset VEYRON_CREDENTIALS
+ # Create two principals, one called "alice" one called "bob"
+ ./principal create ./alice alice >/dev/null || shell_test::fail "line ${LINENO}: create failed"
+ ./principal create ./bob bob >/dev/null || shell_test::fail "line ${LINENO}: create failed"
+ # Run dump, bless, blessself on alice
+ export VEYRON_CREDENTIALS=./alice
+ ./principal blessself alicereborn >alice.blessself || shell_test::fail "line ${LINENO}: blessself failed"
+ ./principal bless ./bob friend >alice.bless || shell_test::fail "line ${LINENO}: bless failed"
+ ./principal dump >alice.dump || shell_test::fail "line ${LINENO}: dump failed"
+ # Run store setdefault, store default, store set, store forpeer on bob
+ export VEYRON_CREDENTIALS=./bob
+ ./principal store setdefault alice.bless || shell_test::fail "line ${LINENO}: store setdefault failed"
+ ./principal store default >bob.store.default || shell_test::fail "line ${LINENO}: store default failed"
+ ./principal store set alice.bless alice/... || shell_test::fail "line ${LINENO}: store set failed"
+ ./principal store forpeer alice/server >bob.store.forpeer || shell_test::fail "line ${LINENO}: store forpeer failed"
+ # Any other commands to be run without VEYRON_CREDENTIALS set.
+ unset VEYRON_CREDENTIALS
- ./principal dump >/dev/null || shell_test::fail "line ${LINENO}: dump failed"
- ./principal blessself >/dev/null || shell_test::fail "line ${LINENO}: blessself failed"
- ./principal blessself alice >alice || shell_test::fail "line ${LINENO}: blessself alice failed"
- ./principal store.default >/dev/null || shell_test::fail "line ${LINENO}: store.default failed"
- ./principal store.forpeer >/dev/null || shell_test::fail "line ${LINENO}: store.forpeer failed"
+ # Validate the output of various commands (mostly using "principal dumpblessings")
+ cat alice.dump | rmpublickey >got || shell_test::fail "line ${LINENO}: cat alice.dump | rmpublickey failed"
+ cat >want <<EOF
+Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+---------------- BlessingStore ----------------
+Default blessings: alice(0 caveats)
+Peer pattern : Blessings
+... : alice(0 caveats)
+---------------- BlessingRoots ----------------
+Public key : Pattern
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [alice/...]
+EOF
+ if ! diff got want; then
+ shell_test::fail "line ${LINENO}"
+ fi
- # Test print
- GOT=$(./principal print alice | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="alice(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
+ dumpblessings alice.blessself >got || shell_test::fail "line ${LINENO}: dumpblessings failed"
+ cat >want <<EOF
+Blessings : alicereborn(0 caveats)
+PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Certificates : 1 chains with (#certificates, #caveats) = (1, 0)
+EOF
+ if ! diff got want; then
+ shell_test::fail "line ${LINENO}"
+ fi
- GOT=$(./principal blessself bob | ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="bob(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
+ dumpblessings bob.store.default >got || shell_test::fail "line ${LINENO}: dumpblessings failed"
+ cat >want <<EOF
+Blessings : alice/friend(1 caveats)
+PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Certificates : 1 chains with (#certificates, #caveats) = (2, 1)
+EOF
+ if ! diff got want; then
+ shell_test::fail "line ${LINENO}"
+ fi
- GOT=$(./principal blessself --for=1h bob| ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="bob(1 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
-
- # Test store.default, store.setdefault
- ./principal blessself testFile >f || shell_test::fail "line ${LINENO}: blessself testFile failed"
- ./principal store.setdefault f || shell_test::fail "line ${LINENO}: store.setdefault failed"
- GOT=$(./principal store.default | ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="testFile(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
-
- ./principal blessself testStdin | ./principal store.setdefault - || shell_test::fail "line ${LINENO}: blessself testStdin | store.setdefault - failed"
- GOT=$(./principal store.default | ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="testStdin(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
-
- # Test store.forpeer, store.set
- ./principal blessself forAlice >f || shell_test::fail "line ${LINENO}: blessself forAlice failed"
- ./principal store.set f alice/... || shell_test::fail "line ${LINENO}: store.set failed"
- ./principal blessself forAll | ./principal store.set - ... || shell_test::fail "line ${LINENO}: blessself forAll | store.set - ... failed"
-
- GOT=$(./principal store.forpeer | ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="forAll(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
-
- GOT=$(./principal store.forpeer bob | ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="forAll(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
-
- GOT=$(./principal store.forpeer alice | ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="forAlice(0 caveats)#forAll(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
-
- GOT=$(./principal store.forpeer alice/friend | ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="forAlice(0 caveats)#forAll(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
-
- GOT=$(./principal store.forpeer alice/friend bob/spouse | ./principal print - | extractBlessings) \
- || shell_test::fail "line ${LINENO}: failed to run principal"
- WANT="forAlice(0 caveats)#forAll(0 caveats)"
- shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
+ dumpblessings bob.store.forpeer >got || shell_test::fail "line ${LINENO}: dumpblessings failed"
+ cat >want <<EOF
+Blessings : bob(0 caveats)#alice/friend(1 caveats)
+PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+Certificates : 2 chains with (#certificates, #caveats) = (1, 0) + (2, 1)
+EOF
+ if ! diff got want; then
+ shell_test::fail "line ${LINENO}"
+ fi
shell_test::pass
}