| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main_test |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io/ioutil" |
| "os" |
| "path/filepath" |
| "regexp" |
| "strings" |
| |
| "v.io/x/ref" |
| "v.io/x/ref/test/v23tests" |
| ) |
| |
| //go:generate v23 test generate |
| |
| // redirect redirects the stdout of the given invocation to the file at the |
| // given path. |
| func redirect(t *v23tests.T, inv *v23tests.Invocation, path string) { |
| if err := ioutil.WriteFile(path, []byte(inv.Output()), 0600); err != nil { |
| t.Fatalf("WriteFile(%q) failed: %v\n", path, err) |
| } |
| } |
| |
| // removePublicKeys 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. |
| func removePublicKeys(input string) string { |
| return regexp.MustCompile("([0-9a-f]{2}:){15}[0-9a-f]{2}").ReplaceAllString(input, "XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX") |
| } |
| |
| func removeCaveats(input string) string { |
| input = regexp.MustCompile(`0xa64c2d0119fba3348071feeb2f308000\(time\.Time=.*\)`).ReplaceAllString(input, "ExpiryCaveat") |
| input = regexp.MustCompile(`0x54a676398137187ecdb26d2d69ba0003\(\[]string=.*\)`).ReplaceAllString(input, "MethodCaveat") |
| input = regexp.MustCompile(`0x00000000000000000000000000000000\(bool=true\)`).ReplaceAllString(input, "Unconstrained") |
| return input |
| } |
| |
| func V23TestBlessSelf(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| aliceDir = filepath.Join(outputDir, "alice") |
| aliceBlessingFile = filepath.Join(outputDir, "aliceself") |
| ) |
| |
| bin := t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| bin.Run("create", aliceDir, "alice") |
| |
| bin = bin.WithEnv(credEnv(aliceDir)) |
| redirect(t, bin.Start("blessself", "alicereborn"), aliceBlessingFile) |
| got := removePublicKeys(bin.Start("dumpblessings", aliceBlessingFile).Output()) |
| want := `Blessings : alicereborn |
| PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate chains : 1 |
| Chain #0 (1 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: alicereborn with 0 caveats |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, wanted \n%s, got\n%s", want, got) |
| } |
| } |
| |
| func V23TestStore(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = filepath.Join(outputDir, "alice") |
| aliceFriend = filepath.Join(outputDir, "alice.bless") |
| bobDir = filepath.Join(outputDir, "bob") |
| bobForPeer = filepath.Join(outputDir, "bob.get.forpeer") |
| ) |
| |
| // Create two principals: alice and bob. |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| bin.Start("create", bobDir, "bob").WaitOrDie(os.Stdout, os.Stderr) |
| |
| // Bless Bob with Alice's principal. |
| blessEnv := credEnv(aliceDir) |
| redirect(t, bin.WithEnv(blessEnv).Start("bless", "--for=1m", bobDir, "friend"), aliceFriend) |
| |
| // Run store forpeer on bob. |
| bin.Start("--v23.credentials="+bobDir, "set", "forpeer", aliceFriend, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| redirect(t, bin.WithEnv(blessEnv).Start("--v23.credentials="+bobDir, "get", "forpeer", "alice/server"), bobForPeer) |
| |
| got := removeCaveats(removePublicKeys(bin.Start("dumpblessings", bobForPeer).Output())) |
| want := `Blessings : bob,alice/friend |
| PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate chains : 2 |
| Chain #0 (1 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: bob with 0 caveats |
| Chain #1 (2 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: alice with 0 caveats |
| Certificate #1: friend with 1 caveat |
| (0) ExpiryCaveat |
| ` |
| if want != got { |
| t.Errorf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| |
| // Test the names flag. |
| got = bin.WithEnv(blessEnv).Start("--v23.credentials="+bobDir, "get", "forpeer", "--names", "alice/server").Output() |
| want = `bob |
| alice/friend |
| ` |
| if got != want { |
| t.Errorf("unexpected output, got %s, want %s", got, want) |
| } |
| |
| // Test the rootkey flag. In particular alice/friend's rootkey should be equal to alice's publickey. |
| got = bin.WithEnv(blessEnv).Start("--v23.credentials="+bobDir, "get", "forpeer", "--rootkey", "alice/friend", "alice/server").Output() |
| want = bin.WithEnv(blessEnv).Start("get", "publickey", "--pretty").Output() |
| if got != want { |
| t.Errorf("unexpected output, got %s, want %s", got, want) |
| } |
| |
| // Test the caveats flag. |
| got = bin.WithEnv(blessEnv).Start("--v23.credentials="+bobDir, "get", "forpeer", "--caveats", "alice/friend", "alice/server").Output() |
| want = "Expires at" |
| if !strings.HasPrefix(got, want) { |
| t.Errorf("unexpected output, got %s, want %s", got, want) |
| } |
| } |
| |
| func V23TestDump(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = filepath.Join(outputDir, "alice") |
| aliceExpiredDir = filepath.Join(outputDir, "alice-expired") |
| ) |
| |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| |
| blessEnv := credEnv(aliceDir) |
| got := removePublicKeys(bin.WithEnv(blessEnv).Start("dump").Output()) |
| want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Default Blessings : alice |
| ---------------- BlessingStore ---------------- |
| Default Blessings alice |
| Peer pattern Blessings |
| ... alice |
| ---------------- BlessingRoots ---------------- |
| Public key Pattern |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [alice] |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| |
| got = bin.WithEnv(blessEnv).Start("dump", "-s").Output() |
| want = "alice\n" |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| |
| bin.Start("--v23.credentials="+aliceDir, "fork", "--for", "-1h", aliceExpiredDir, "expired").WaitOrDie(os.Stdout, os.Stderr) |
| blessEnv = credEnv(aliceExpiredDir) |
| got = removePublicKeys(bin.WithEnv(blessEnv).Start("dump").Output()) |
| want = `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Default Blessings : alice/expired [EXPIRED] |
| ---------------- BlessingStore ---------------- |
| Default Blessings alice/expired |
| Peer pattern Blessings |
| ... alice/expired |
| ---------------- BlessingRoots ---------------- |
| Public key Pattern |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [alice] |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| |
| got = bin.WithEnv(blessEnv).Start("dump", "-s").Output() |
| want = "alice/expired [EXPIRED]\n" |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| |
| func V23TestGetRecognizedRoots(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = filepath.Join(outputDir, "alice") |
| ) |
| |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| |
| blessEnv := credEnv(aliceDir) |
| got := removePublicKeys(bin.WithEnv(blessEnv).Start("get", "recognizedroots").Output()) |
| want := `Public key Pattern |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [alice] |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| |
| func V23TestGetPeermap(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = filepath.Join(outputDir, "alice") |
| ) |
| |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| |
| blessEnv := credEnv(aliceDir) |
| got := bin.WithEnv(blessEnv).Start("get", "peermap").Output() |
| want := `Default Blessings alice |
| Peer pattern Blessings |
| ... alice |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| |
| // Given an invocation of "principal recvblessings", this function returns the |
| // arguments to provide to "principal bless" provided by the "recvblessings" |
| // invocation. |
| // |
| // For example, |
| // principal recvblessings |
| // would typically print something like: |
| // principal bless --remote-key=<some_public_key> --remote-token=<some_token> extensionfoo |
| // as an example of command line to use to send the blessings over. |
| // |
| // In that case, this method would return: |
| // { "--remote-key=<some_public_key>", "--remote-token=<some_token>", "extensionfoo"} |
| func blessArgsFromRecvBlessings(inv *v23tests.Invocation) []string { |
| cmd := inv.ExpectSetEventuallyRE("(^principal bless .*$)")[0][0] |
| return strings.Split(cmd, " ")[2:] |
| } |
| |
| func V23TestRecvBlessings(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = filepath.Join(outputDir, "alice") |
| bobDir = filepath.Join(outputDir, "bob") |
| carolDir = filepath.Join(outputDir, "carol") |
| bobBlessFile = filepath.Join(outputDir, "bobBlessInfo") |
| ) |
| |
| // Generate principals |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| bin.Start("create", bobDir, "bob").WaitOrDie(os.Stdout, os.Stderr) |
| bin.Start("create", carolDir, "carol").WaitOrDie(os.Stdout, os.Stderr) |
| |
| // Run recvblessings on carol, and have alice send blessings over |
| // (blessings received must be set as default and shareable with all peers). |
| var args []string |
| { |
| inv := bin.Start("--v23.credentials="+carolDir, "--v23.tcp.address=127.0.0.1:0", "recvblessings") |
| args = append([]string{"bless", "--require-caveats=false"}, blessArgsFromRecvBlessings(inv)...) |
| // Use the "friend/carol" extension |
| args = append(args, "friend/carol") |
| } |
| bin.WithEnv(credEnv(aliceDir)).Start(args...).WaitOrDie(os.Stdout, os.Stderr) |
| |
| // Run recvblessings on carol, and have alice send blessings over |
| // (blessings received must be set as shareable with peers matching 'alice/...'.) |
| { |
| inv := bin.Start("--v23.credentials="+carolDir, "--v23.tcp.address=127.0.0.1:0", "recvblessings", "--for-peer=alice", "--set-default=false") |
| // recvblessings suggests a random extension, find the extension and replace it with friend/carol/foralice. |
| args = append([]string{"bless", "--require-caveats=false"}, blessArgsFromRecvBlessings(inv)...) |
| args = append(args, "friend/carol/foralice") |
| } |
| bin.WithEnv(credEnv(aliceDir)).Start(args...).WaitOrDie(os.Stdout, os.Stderr) |
| |
| // Run recvblessings on carol with the --remote-arg-file flag, and have bob send blessings over with the --remote-arg-file flag. |
| { |
| inv := bin.Start("--v23.credentials="+carolDir, "--v23.tcp.address=127.0.0.1:0", "recvblessings", "--for-peer=bob", "--set-default=false", "--remote-arg-file="+bobBlessFile) |
| // recvblessings suggests a random extension, use friend/carol/forbob instead. |
| args = append([]string{"bless", "--require-caveats=false"}, blessArgsFromRecvBlessings(inv)...) |
| args = append(args, "friend/carol/forbob") |
| } |
| bin.WithEnv(credEnv(bobDir)).Start(args...).WaitOrDie(os.Stdout, os.Stderr) |
| |
| listenerInv := bin.Start("--v23.credentials="+carolDir, "--v23.tcp.address=127.0.0.1:0", "recvblessings", "--for-peer=alice/...", "--set-default=false", "--vmodule=*=2", "--logtostderr") |
| |
| args = append([]string{"bless", "--require-caveats=false"}, blessArgsFromRecvBlessings(listenerInv)...) |
| args = append(args, "willfail") |
| |
| { |
| // Mucking around with remote-key should fail. |
| cpy := strings.Split(regexp.MustCompile("remote-key=").ReplaceAllString(strings.Join(args, " "), "remote-key=BAD"), " ") |
| var buf bytes.Buffer |
| if bin.WithEnv(credEnv(aliceDir)).Start(cpy...).Wait(os.Stdout, &buf) == nil { |
| t.Fatalf("%v should have failed, but did not", cpy) |
| } |
| |
| if want, got := "key mismatch", buf.String(); !strings.Contains(got, want) { |
| t.Fatalf("expected %q to be contained within\n%s\n, but was not", want, got) |
| } |
| } |
| |
| { |
| var buf bytes.Buffer |
| // Mucking around with the token should fail. |
| cpy := strings.Split(regexp.MustCompile("remote-token=").ReplaceAllString(strings.Join(args, " "), "remote-token=BAD"), " ") |
| if bin.WithEnv(credEnv(aliceDir)).Start(cpy...).Wait(os.Stdout, &buf) == nil { |
| t.Fatalf("%v should have failed, but did not", cpy) |
| } |
| |
| if want, got := "blessings received from unexpected sender", buf.String(); !strings.Contains(got, want) { |
| t.Fatalf("expected %q to be contained within\n%s\n, but was not", want, got) |
| } |
| } |
| |
| // Dump carol out, the only blessing that survives should be from the |
| // first "bless" command. (alice/friend/carol). |
| got := removePublicKeys(bin.Start("--v23.credentials="+carolDir, "dump").Output()) |
| want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Default Blessings : alice/friend/carol |
| ---------------- BlessingStore ---------------- |
| Default Blessings alice/friend/carol |
| Peer pattern Blessings |
| ... alice/friend/carol |
| alice alice/friend/carol/foralice |
| bob bob/friend/carol/forbob |
| ---------------- BlessingRoots ---------------- |
| Public key Pattern |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [alice] |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [bob] |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [carol] |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| |
| func V23TestRecvBlessingsInteractive(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = filepath.Join(outputDir, "alice") |
| bobDir = filepath.Join(outputDir, "bob") |
| aliceBin = bin.WithEnv(credEnv(aliceDir)) |
| ) |
| |
| // Generate principals |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| bin.Start("create", bobDir, "bob").WaitOrDie(os.Stdout, os.Stderr) |
| |
| // Run recvblessings on bob |
| recv := bin.Start("--v23.credentials="+bobDir, "--v23.tcp.address=127.0.0.1:0", "recvblessings") |
| args := blessArgsFromRecvBlessings(recv) |
| |
| // When running the exact command, must be prompted about caveats. |
| { |
| inv := aliceBin.Start(append([]string{"bless"}, args...)...) |
| inv.Expect("WARNING: No caveats provided") |
| // Saying something other than "yes" or "YES" |
| // should fail. |
| fmt.Fprintln(inv.Stdin(), "yeah") |
| if err := inv.Wait(os.Stdout, os.Stderr); err == nil { |
| t.Fatalf("Expected principal bless to fail because the wrong input was provided") |
| } |
| } |
| // When agreeing to have no caveats, must specify an extension |
| { |
| inv := aliceBin.Start(append([]string{"bless"}, args...)...) |
| inv.Expect("WARNING: No caveats provided") |
| fmt.Fprintln(inv.Stdin(), "yes") |
| inv.CloseStdin() |
| if err := inv.Wait(os.Stdout, os.Stderr); err == nil { |
| t.Fatalf("Expected principal bless to fail because no extension was provided") |
| } |
| } |
| // When providing both, the bless command should succeed. |
| { |
| inv := aliceBin.Start(append([]string{"bless"}, args...)...) |
| fmt.Fprintln(inv.Stdin(), "YES") |
| fmt.Fprintln(inv.Stdin(), "friend/bobby") |
| if err := inv.Wait(os.Stdout, os.Stderr); err != nil { |
| t.Fatal(err) |
| } |
| } |
| got := removePublicKeys(bin.Start("--v23.credentials="+bobDir, "dump").Output()) |
| want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Default Blessings : alice/friend/bobby |
| ---------------- BlessingStore ---------------- |
| Default Blessings alice/friend/bobby |
| Peer pattern Blessings |
| ... alice/friend/bobby |
| ---------------- BlessingRoots ---------------- |
| Public key Pattern |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [alice] |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [bob] |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| |
| func V23TestFork(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = filepath.Join(outputDir, "alice") |
| alicePhoneDir = filepath.Join(outputDir, "alice-phone") |
| alicePhoneCalendarDir = filepath.Join(outputDir, "alice-phone-calendar") |
| tmpfile = filepath.Join(outputDir, "tmpfile") |
| ) |
| |
| // Generate principals for alice. |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| |
| // Run fork to setup up credentials for alice/phone that are |
| // blessed by alice under the extension "phone". |
| bin.Start("--v23.credentials="+aliceDir, "fork", "--for", "1h", alicePhoneDir, "phone").WaitOrDie(os.Stdout, os.Stderr) |
| |
| // Dump alice-phone out, the only blessings it has must be from alice (alice/phone). |
| { |
| got := removePublicKeys(bin.Start("--v23.credentials="+alicePhoneDir, "dump").Output()) |
| want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Default Blessings : alice/phone |
| ---------------- BlessingStore ---------------- |
| Default Blessings alice/phone |
| Peer pattern Blessings |
| ... alice/phone |
| ---------------- BlessingRoots ---------------- |
| Public key Pattern |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [alice] |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| // And it should have an expiry caveat |
| { |
| redirect(t, bin.Start("--v23.credentials", alicePhoneDir, "get", "default"), tmpfile) |
| got := removeCaveats(removePublicKeys(bin.Start("dumpblessings", tmpfile).Output())) |
| want := `Blessings : alice/phone |
| PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate chains : 1 |
| Chain #0 (2 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: alice with 0 caveats |
| Certificate #1: phone with 1 caveat |
| (0) ExpiryCaveat |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| |
| // Run fork to setup up credentials for alice/phone/calendar that are |
| // blessed by alice/phone under the extension "calendar". |
| bin.Start("--v23.credentials="+alicePhoneDir, "fork", "--for", "1h", alicePhoneCalendarDir, "calendar").WaitOrDie(os.Stdout, os.Stderr) |
| { |
| got := removePublicKeys(bin.Start("--v23.credentials="+alicePhoneCalendarDir, "dump").Output()) |
| want := `Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Default Blessings : alice/phone/calendar |
| ---------------- BlessingStore ---------------- |
| Default Blessings alice/phone/calendar |
| Peer pattern Blessings |
| ... alice/phone/calendar |
| ---------------- BlessingRoots ---------------- |
| Public key Pattern |
| XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX [alice] |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| { |
| redirect(t, bin.Start("--v23.credentials", alicePhoneCalendarDir, "get", "default"), tmpfile) |
| got := removeCaveats(removePublicKeys(bin.Start("dumpblessings", tmpfile).Output())) |
| want := `Blessings : alice/phone/calendar |
| PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate chains : 1 |
| Chain #0 (3 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: alice with 0 caveats |
| Certificate #1: phone with 1 caveat |
| (0) ExpiryCaveat |
| Certificate #2: calendar with 1 caveat |
| (0) ExpiryCaveat |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, got\n%s, wanted\n%s", got, want) |
| } |
| } |
| } |
| |
| func V23TestCreate(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = filepath.Join(outputDir, "alice") |
| ) |
| |
| // Creating a principal should succeed the first time. |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| |
| // The second time should fail (the create command won't override an existing principal). |
| if bin.Start("create", aliceDir, "alice").Wait(os.Stdout, os.Stderr) == nil { |
| t.Fatalf("principal creation should have failed, but did not") |
| } |
| |
| // If we specify -overwrite, it will. |
| bin.Start("create", "--overwrite", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| } |
| |
| func V23TestCaveats(t *v23tests.T) { |
| var ( |
| outputDir = t.NewTempDir("") |
| aliceDir = filepath.Join(outputDir, "alice") |
| aliceBlessingFile = filepath.Join(outputDir, "aliceself") |
| ) |
| |
| bin := t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| |
| bin = bin.WithEnv(credEnv(aliceDir)) |
| args := []string{ |
| "blessself", |
| "--caveat=\"v.io/v23/security\".MethodCaveat={\"method\"}", |
| "--caveat={{0x54,0xa6,0x76,0x39,0x81,0x37,0x18,0x7e,0xcd,0xb2,0x6d,0x2d,0x69,0xba,0x0,0x3},typeobject([]string)}={\"method\"}", |
| "alicereborn", |
| } |
| redirect(t, bin.Start(args...), aliceBlessingFile) |
| got := removeCaveats(removePublicKeys(bin.Start("dumpblessings", aliceBlessingFile).Output())) |
| want := `Blessings : alicereborn |
| PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate chains : 1 |
| Chain #0 (1 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: alicereborn with 2 caveats |
| (0) MethodCaveat |
| (1) MethodCaveat |
| ` |
| if want != got { |
| t.Fatalf("unexpected output, wanted \n%s, got\n%s", want, got) |
| } |
| } |
| |
| func V23TestForkWithoutVDLPATH(t *v23tests.T) { |
| var ( |
| parent = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal").WithEnv("V23_ROOT=''", "VDLPATH=''") |
| ) |
| if err := bin.Start("create", parent, "parent").Wait(os.Stdout, os.Stderr); err != nil { |
| t.Fatalf("create %q failed: %v", parent, err) |
| } |
| if err := bin.Start("--v23.credentials="+parent, "fork", "--for=1s", t.NewTempDir(""), "child").Wait(os.Stdout, os.Stderr); err != nil { |
| t.Errorf("fork failed: %v", err) |
| } |
| } |
| |
| func V23TestForkWithoutCaveats(t *v23tests.T) { |
| var ( |
| parent = t.NewTempDir("") |
| child = t.NewTempDir("") |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| buf bytes.Buffer |
| ) |
| if err := bin.Start("create", parent, "parent").Wait(os.Stdout, os.Stderr); err != nil { |
| t.Fatalf("create %q failed: %v", parent, err) |
| } |
| if err := bin.Start("--v23.credentials", parent, "fork", child, "child").Wait(os.Stdout, &buf); err == nil { |
| t.Errorf("fork should have failed without any caveats, but did not") |
| } else if got, want := buf.String(), "ERROR: no caveats provided"; !strings.Contains(got, want) { |
| t.Errorf("fork returned error: %q, expected error to contain %q", got, want) |
| } |
| if err := bin.Start("--v23.credentials", parent, "fork", "--for=0", child, "child").Wait(os.Stdout, &buf); err == nil { |
| t.Errorf("fork should have failed without any caveats, but did not") |
| } else if got, want := buf.String(), "ERROR: no caveats provided"; !strings.Contains(got, want) { |
| t.Errorf("fork returned error: %q, expected error to contain %q", got, want) |
| } |
| if err := bin.Start("--v23.credentials", parent, "fork", "--require-caveats=false", child, "child").Wait(os.Stdout, os.Stderr); err != nil { |
| t.Errorf("fork --require-caveats=false failed with: %v", err) |
| } |
| } |
| |
| func V23TestBless(t *v23tests.T) { |
| var ( |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| dir = t.NewTempDir("") |
| aliceDir = filepath.Join(dir, "alice") |
| bobDir = filepath.Join(dir, "bob") |
| tmpfile = filepath.Join(dir, "tmpfile") |
| ) |
| // Create two principals: alice and bob |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| bin.Start("create", bobDir, "bob").WaitOrDie(os.Stdout, os.Stderr) |
| |
| // All blessings will be done by "alice" |
| bin = bin.WithEnv(credEnv(aliceDir)) |
| |
| { |
| // "alice" should fail to bless "bob" without any caveats |
| var buf bytes.Buffer |
| if err := bin.Start("bless", bobDir, "friend").Wait(os.Stdout, &buf); err == nil { |
| t.Errorf("bless should have failed when no caveats are specified") |
| } else if got, want := buf.String(), "ERROR: no caveats provided"; !strings.Contains(got, want) { |
| t.Errorf("got error %q, expected to match %q", got, want) |
| } |
| } |
| { |
| // But succeed if --require-caveats=false is specified |
| redirect(t, bin.Start("bless", "--require-caveats=false", bobDir, "friend"), tmpfile) |
| got := removeCaveats(removePublicKeys(bin.Start("dumpblessings", tmpfile).Output())) |
| want := `Blessings : alice/friend |
| PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate chains : 1 |
| Chain #0 (2 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: alice with 0 caveats |
| Certificate #1: friend with 1 caveat |
| (0) Unconstrained |
| ` |
| if got != want { |
| t.Errorf("Got\n%vWant\n%v", got, want) |
| } |
| } |
| { |
| // And succeed if --for is specified |
| redirect(t, bin.Start("bless", "--for=1m", bobDir, "friend"), tmpfile) |
| got := removeCaveats(removePublicKeys(bin.Start("dumpblessings", tmpfile).Output())) |
| want := `Blessings : alice/friend |
| PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate chains : 1 |
| Chain #0 (2 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: alice with 0 caveats |
| Certificate #1: friend with 1 caveat |
| (0) ExpiryCaveat |
| ` |
| if got != want { |
| t.Errorf("Got\n%vWant\n%v", got, want) |
| } |
| } |
| { |
| // If the Blessings are expired, dumpBlessings should print so. |
| redirect(t, bin.Start("bless", "--for=-1s", bobDir, "friend"), tmpfile) |
| got := removeCaveats(removePublicKeys(bin.Start("dumpblessings", tmpfile).Output())) |
| want := `Blessings : alice/friend [EXPIRED] |
| PublicKey : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate chains : 1 |
| Chain #0 (2 certificates). Root certificate public key: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX |
| Certificate #0: alice with 0 caveats |
| Certificate #1: friend with 1 caveat |
| (0) ExpiryCaveat |
| ` |
| if got != want { |
| t.Errorf("Got\n%vWant\n%v", got, want) |
| } |
| } |
| { |
| // But not if --for=0 |
| var buf bytes.Buffer |
| if err := bin.Start("bless", "--for=0", bobDir, "friend").Wait(os.Stdout, &buf); err == nil { |
| t.Errorf("bless should have failed when no caveats are specified") |
| } else if got, want := buf.String(), "ERROR: no caveats provided"; !strings.Contains(got, want) { |
| t.Errorf("got error %q, expected to match %q", got, want) |
| } |
| } |
| } |
| |
| func V23TestAddBlessingsToRoots(t *v23tests.T) { |
| var ( |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| aliceDir = t.NewTempDir("") |
| bobDir = t.NewTempDir("") |
| blessingFile = filepath.Join(t.NewTempDir(""), "bobfile") |
| |
| // Extract the public key from the first line of output from |
| // "principal dump", which is formatted as: |
| // Public key : <the public key> |
| publicKey = func(dir string) string { |
| output := bin.Start("--v23.credentials="+dir, "dump").Output() |
| line := strings.SplitN(output, "\n", 2)[0] |
| fields := strings.Split(line, " ") |
| return fields[len(fields)-1] |
| } |
| ) |
| // Create two principals, "alice" and "bob" |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| bin.Start("create", bobDir, "bob").WaitOrDie(os.Stdout, os.Stderr) |
| // Have bob create a "bob/friend" blessing and have alice recognize that. |
| redirect(t, bin.Start("--v23.credentials="+bobDir, "bless", "--require-caveats=false", aliceDir, "friend"), blessingFile) |
| bin.Start("--v23.credentials="+aliceDir, "recognize", blessingFile).WaitOrDie(os.Stdout, os.Stderr) |
| |
| want := fmt.Sprintf(`Public key Pattern |
| %v [alice] |
| %v [bob] |
| `, publicKey(aliceDir), publicKey(bobDir)) |
| |
| // Finally view alice's recognized roots, it should have lines corresponding to aliceLine and bobLine. |
| got := bin.Start("--v23.credentials="+aliceDir, "get", "recognizedroots").Output() |
| if got != want { |
| t.Fatalf("Got:\n%v\n\nWant:\n%v", got, want) |
| } |
| } |
| |
| func V23TestAddKeyToRoots(t *v23tests.T) { |
| var ( |
| bin = t.BuildGoPkg("v.io/x/ref/cmd/principal") |
| outputDir = t.NewTempDir("") |
| aliceDir = filepath.Join(outputDir, "alice") |
| bobDir = filepath.Join(outputDir, "bob") |
| ) |
| bin.Start("create", aliceDir, "alice").WaitOrDie(os.Stdout, os.Stderr) |
| bin.Start("create", bobDir, "bob").WaitOrDie(os.Stdout, os.Stderr) |
| // Get bob's public key and add it to roots for alice |
| bobKey := strings.TrimSpace(bin.Start("--v23.credentials="+bobDir, "get", "publickey").Output()) |
| bobPrettyKey := strings.TrimSpace(bin.Start("--v23.credentials="+bobDir, "get", "publickey", "--pretty").Output()) |
| bin.Start("--v23.credentials="+aliceDir, "recognize", "bob", bobKey).WaitOrDie(os.Stdout, os.Stderr) |
| |
| // Verify that it has been added |
| output := bin.Start("--v23.credentials="+aliceDir, "dump").Output() |
| want := fmt.Sprintf("%v [bob]", bobPrettyKey) |
| for _, line := range strings.Split(output, "\n") { |
| if line == want { |
| return |
| } |
| } |
| t.Errorf("Could not find line:\n%v\nin output:\n%v\n", want, output) |
| } |
| |
| func credEnv(dir string) string { |
| return fmt.Sprintf("%s=%s", ref.EnvCredentials, dir) |
| } |