security: Make agent integration tests actually test something :)
Somewhere between the transition from shell scripts to the v23tests
package and the "context.T" refactoring and the mounttable
authorization, the agent integration tests were rendered mostly useless
- the tests would pass even if agent credentials are not propagated.
This commit addresses that and hopefully makes the tests easier to
follow.
Some specific changes:
- The pingpong test helper binary now actually performs server
authorization using the default authorization policy instead of
allowing any blessing through.
The binary also does not add any security skipping options
(like SkipResolveAuthorization)
Thus, for a client to successfully ping a server, it needs
to present blessings that are delegations from the server.
- The same binary uses a real runtime/context using v23.Init
instead of test.InitForTest
- The tests do not depend on a running mounttable daemon.
- Use the v23tests library correctly: Calling v23tests.Invocation.Expect*
is mostly futile if the Error method is not going to be called after
waiting for the invocation to terminate.
- No need for a helper binary for testing vrun.
Change-Id: I372ded786357d5e5d46591774626971cc462de79
diff --git a/cmd/vrun/internal/vrun_test_helper.go b/cmd/vrun/internal/vrun_test_helper.go
deleted file mode 100644
index 97e26ab..0000000
--- a/cmd/vrun/internal/vrun_test_helper.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
-)
-
-// Helper script for testing vrun.
-func main() {
- if len(os.Args) != 4 {
- fmt.Fprintf(os.Stderr, "usage: %s <vrun_path> <pingpong_path> <principal_path>\n", os.Args[0])
- os.Exit(1)
- }
-
- vrunPath := os.Args[1]
- pingpongPath := os.Args[2]
- principalPath := os.Args[3]
-
- if output, err := exec.Command(principalPath, "dump").Output(); err != nil {
- fmt.Fprintf(os.Stderr, "could not run %s dump\n", principalPath)
- os.Exit(1)
- } else {
- if want := "Default blessings: agent_principal"; !strings.Contains(string(output), want) {
- fmt.Fprintf(os.Stderr, "expected output to contain %s, but did not. Output was:\n%s\n")
- os.Exit(1)
- }
- }
-
- if output, err := exec.Command(vrunPath, principalPath, "dump").Output(); err != nil {
- fmt.Fprintf(os.Stderr, "could not run %s %s dump\n", vrunPath, principalPath)
- os.Exit(1)
- } else {
- if want := "Default blessings: agent_principal/principal"; !strings.Contains(string(output), want) {
- fmt.Fprintf(os.Stderr, "expected output to contain %s, but did not. Output was:\n%s\n")
- os.Exit(1)
- }
- }
-
- if output, err := exec.Command(vrunPath, "--name=foo", principalPath, "dump").Output(); err != nil {
- fmt.Fprintf(os.Stderr, "could not run %s %s dump\n", vrunPath, principalPath)
- os.Exit(1)
- } else {
- if want := "Default blessings: agent_principal/foo"; !strings.Contains(string(output), want) {
- fmt.Fprintf(os.Stderr, "expected output to contain %s, but did not. Output was:\n%s\n")
- os.Exit(1)
- }
- }
-
- server, err := os.StartProcess(vrunPath, []string{filepath.Base(vrunPath), pingpongPath, "--server"}, &os.ProcAttr{})
- defer func() {
- if server != nil {
- server.Kill()
- }
- }()
- if err != nil {
- fmt.Fprintf(os.Stderr, "could not start server: %v\n", err)
- os.Exit(1)
- }
-
- if output, err := exec.Command(vrunPath, pingpongPath).Output(); err != nil {
- fmt.Fprintf(os.Stderr, "could not start client: %v\n", err)
- os.Exit(1)
- } else {
- fmt.Fprintf(os.Stdout, "Received output: %s\n", output)
- }
-}
diff --git a/cmd/vrun/internal/vrun_v23_test.go b/cmd/vrun/internal/vrun_v23_test.go
deleted file mode 100644
index ffe16b5..0000000
--- a/cmd/vrun/internal/vrun_v23_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package main_test
-
-//go:generate v23 test generate .
-
-import (
- "os"
-
- _ "v.io/x/ref/profiles/static"
- "v.io/x/ref/test/v23tests"
-)
-
-func V23TestAgentd(t *v23tests.T) {
- vrunBin := t.BuildGoPkg("v.io/x/ref/cmd/vrun")
- pingpongBin := t.BuildGoPkg("v.io/x/ref/security/agent/pingpong")
- agentdBin := t.BuildGoPkg("v.io/x/ref/security/agent/agentd")
- helperBin := t.BuildGoPkg("v.io/x/ref/cmd/vrun/internal")
- principalBin := t.BuildGoPkg("v.io/x/ref/cmd/principal")
-
- v23tests.RunRootMT(t, "--veyron.tcp.address=127.0.0.1:0")
-
- creds := t.NewTempDir()
- agentdBin.WithEnv("VEYRON_CREDENTIALS="+creds).Start("--no_passphrase",
- "--additional_principals="+creds,
- helperBin.Path(),
- vrunBin.Path(),
- pingpongBin.Path(),
- principalBin.Path()).WaitOrDie(os.Stdout, os.Stderr)
-}
diff --git a/cmd/vrun/internal/v23_test.go b/cmd/vrun/v23_test.go
similarity index 100%
rename from cmd/vrun/internal/v23_test.go
rename to cmd/vrun/v23_test.go
diff --git a/cmd/vrun/vrun_v23_test.go b/cmd/vrun/vrun_v23_test.go
new file mode 100644
index 0000000..161b84d
--- /dev/null
+++ b/cmd/vrun/vrun_v23_test.go
@@ -0,0 +1,103 @@
+package main_test
+
+//go:generate v23 test generate .
+
+import (
+ "fmt"
+ "os"
+
+ "v.io/v23/security"
+
+ vsecurity "v.io/x/ref/security"
+ "v.io/x/ref/test/v23tests"
+)
+
+func V23TestAgentd(t *v23tests.T) {
+ var (
+ clientAgent, serverAgent = createClientAndServerAgents(t)
+ tmpdir = t.NewTempDir()
+ vrun = t.BuildGoPkg("v.io/x/ref/cmd/vrun").Path()
+ pingpong = t.BuildGoPkg("v.io/x/ref/security/agent/pingpong").Path()
+ serverName = serverAgent.Start(pingpong).ExpectVar("NAME")
+
+ tests = []struct {
+ Command []string
+ Client string
+ }{
+ {
+ []string{pingpong, serverName}, // No vrun
+ "pingpongd/client",
+ },
+ {
+ []string{vrun, pingpong, serverName},
+ "pingpongd/client/pingpong",
+ },
+ {
+ []string{vrun, "--name=bugsy", pingpong, serverName},
+ "pingpongd/client/bugsy",
+ },
+ }
+ )
+ for _, test := range tests {
+ args := append([]string{"--additional_principals=" + tmpdir}, test.Command...)
+ client := clientAgent.Start(args...)
+ client.Expect("Pinging...")
+ client.Expect(fmt.Sprintf("pong (client:[%v] server:[pingpongd])", test.Client))
+ client.WaitOrDie(os.Stdout, os.Stderr)
+ if err := client.Error(); err != nil {
+ t.Errorf("Test: %+v: %v", test, err)
+ }
+ }
+}
+
+// createClientAndServerAgents creates two principals, sets up their
+// blessings and returns the agent binaries that will use the created credentials.
+//
+// The server will have a single blessing "pingpongd".
+// The client will have a single blessing "pingpongd/client", blessed by the server.
+func createClientAndServerAgents(i *v23tests.T) (client, server *v23tests.Binary) {
+ var (
+ agentd = i.BuildGoPkg("v.io/x/ref/security/agent/agentd")
+ clientDir = i.NewTempDir()
+ serverDir = i.NewTempDir()
+ )
+ pserver, err := vsecurity.CreatePersistentPrincipal(serverDir, nil)
+ if err != nil {
+ i.Fatal(err)
+ }
+ pclient, err := vsecurity.CreatePersistentPrincipal(clientDir, nil)
+ if err != nil {
+ i.Fatal(err)
+ }
+ // Server will only serve, not make any client requests, so only needs a default blessing.
+ bserver, err := pserver.BlessSelf("pingpongd")
+ if err != nil {
+ i.Fatal(err)
+ }
+ if err := pserver.BlessingStore().SetDefault(bserver); err != nil {
+ i.Fatal(err)
+ }
+ // Clients need not have a default blessing as they will only make a request to the server.
+ bclient, err := pserver.Bless(pclient.PublicKey(), bserver, "client", security.UnconstrainedUse())
+ if err != nil {
+ i.Fatal(err)
+ }
+ if _, err := pclient.BlessingStore().Set(bclient, "pingpongd"); err != nil {
+ i.Fatal(err)
+ }
+ // The client and server must both recognize bserver and its delegates.
+ if err := pserver.AddToRoots(bserver); err != nil {
+ i.Fatal(err)
+ }
+ if err := pclient.AddToRoots(bserver); err != nil {
+ i.Fatal(err)
+ }
+ // TODO(ashankar,ribrdb,suharshs): This should not be needed. It seems
+ // however, that not providing it messes up the agent: Specifically,
+ // the child process is unable to connect to the agent?
+ if err := pclient.BlessingStore().SetDefault(bclient); err != nil {
+ i.Fatal(err)
+ }
+ const envvar = "VEYRON_CREDENTIALS="
+ return agentd.WithEnv(envvar + clientDir), agentd.WithEnv(envvar + serverDir)
+}
diff --git a/security/agent/agent_v23_test.go b/security/agent/agent_v23_test.go
index 5c46db9..1d5446a 100644
--- a/security/agent/agent_v23_test.go
+++ b/security/agent/agent_v23_test.go
@@ -6,167 +6,259 @@
"io/ioutil"
"os"
"path/filepath"
- "runtime"
"strings"
+ "text/template"
+ "v.io/v23/security"
+ vsecurity "v.io/x/ref/security"
"v.io/x/ref/test/v23tests"
)
//go:generate v23 test generate
func V23TestTestPassPhraseUse(i *v23tests.T) {
- // Test passphrase handling.
-
- bin := i.BuildGoPkg("v.io/x/ref/security/agent/agentd")
- credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
+ bin := i.BuildGoPkg("v.io/x/ref/security/agent/agentd").WithEnv("VEYRON_CREDENTIALS=" + i.NewTempDir())
// Create the passphrase
- agent := bin.WithEnv(credentials).Start("echo", "Hello")
+ agent := bin.Start("echo", "Hello")
fmt.Fprintln(agent.Stdin(), "PASSWORD")
agent.ReadLine() // Skip over ...creating new key... message
agent.Expect("Hello")
agent.ExpectEOF()
+ if err := agent.Error(); err != nil {
+ i.Fatal(err)
+ }
+
// Use it successfully
- agent = bin.WithEnv(credentials).Start("echo", "Hello")
+ agent = bin.Start("echo", "Hello")
fmt.Fprintln(agent.Stdin(), "PASSWORD")
agent.Expect("Hello")
agent.ExpectEOF()
+ if err := agent.Error(); err != nil {
+ i.Fatal(err)
+ }
- agent = bin.WithEnv(credentials).Start("echo", "Hello")
+ // Provide a bad password
+ agent = bin.Start("echo", "Hello")
fmt.Fprintln(agent.Stdin(), "BADPASSWORD")
agent.ExpectEOF()
- stderr := bytes.Buffer{}
- err := agent.Wait(nil, &stderr)
- if err == nil {
- i.Fatalf("expected an error!")
+ var stdout, stderr bytes.Buffer
+ if err := agent.Wait(&stdout, &stderr); err == nil {
+ i.Fatalf("expected an error.STDOUT:%v\nSTDERR:%v\n", stdout.String(), stderr.String())
+ } else if got, want := err.Error(), "exit status 255"; got != want {
+ i.Fatalf("Got %q, want %q", got, want)
+ } else if got, want := stderr.String(), "passphrase incorrect for decrypting private key"; !strings.Contains(got, want) {
+ i.Fatalf("Got %q, wanted it to contain %q", got, want)
}
- if got, want := err.Error(), "exit status 255"; got != want {
- i.Fatalf("got %q, want %q", got, want)
- }
- if got, want := stderr.String(), "passphrase incorrect for decrypting private key"; !strings.Contains(got, want) {
- i.Fatalf("%q doesn't contain %q", got, want)
+ if err := agent.Error(); err != nil {
+ i.Fatal(err)
}
}
func V23TestAllPrincipalMethods(i *v23tests.T) {
// Test all methods of the principal interface.
// (Errors are printed to STDERR)
- agentBin := i.BuildGoPkg("v.io/x/ref/security/agent/agentd")
- principalBin := i.BuildGoPkg("v.io/x/ref/security/agent/test_principal")
-
- credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
- agent := agentBin.WithEnv(credentials).Start(principalBin.Path())
- agent.WaitOrDie(nil, os.Stderr)
-}
-
-func buildAndRunPingpongServer(i *v23tests.T, rootMTArg string) *v23tests.Binary {
- pingpongBin := i.BuildGoPkg("v.io/x/ref/security/agent/pingpong")
- pingpongServer := pingpongBin.Start("--server", rootMTArg)
- // Make sure pingpong is up and running.
- pingpongServer.ExpectRE(".*Listening at.*", -1)
- return pingpongBin
+ testbin := i.BuildGoPkg("v.io/x/ref/security/agent/test_principal").Path()
+ i.BuildGoPkg("v.io/x/ref/security/agent/agentd").
+ WithEnv("VEYRON_CREDENTIALS="+i.NewTempDir()).
+ Start(testbin).
+ WaitOrDie(nil, os.Stderr)
}
func V23TestAgentProcesses(i *v23tests.T) {
- // Test that the agent can correctly run one or more subproccesses.
- v23tests.RunRootMT(i, "--veyron.tcp.address=127.0.0.1:0")
+ // Setup two principals: One for the agent that runs the pingpong
+ // server, one for the client. Since the server uses the default
+ // authorization policy, the client must have a blessing delegated from
+ // the server.
+ var (
+ clientAgent, serverAgent = createClientAndServerAgents(i)
+ pingpong = i.BuildGoPkg("v.io/x/ref/security/agent/pingpong").Path()
+ serverName = serverAgent.Start(pingpong).ExpectVar("NAME")
+ )
+ // Run the client via an agent once.
+ client := clientAgent.Start(pingpong, serverName)
+ client.Expect("Pinging...")
+ client.Expect("pong (client:[pingpongd/client] server:[pingpongd])")
+ client.WaitOrDie(os.Stdout, os.Stderr)
+ if err := client.Error(); err != nil { // Check expectations
+ i.Fatal(err)
+ }
- // The agent doesn't pass NAMESPACE_ROOT or other env vars through to its
- // children, so we have to pass them specifically to the commands
- // we ask it to run.
- rootMT, _ := i.GetVar("NAMESPACE_ROOT")
- rootMTArg := "--veyron.namespace.root=" + rootMT
+ // Run it through a shell to test that the agent can pass credentials
+ // to subprocess of a shell (making things like "agentd bash" provide
+ // useful terminals).
+ // This only works with shells that propagate open file descriptors to
+ // children. POSIX-compliant shells do this as to many other commonly
+ // used ones like bash.
+ script := filepath.Join(i.NewTempDir(), "test.sh")
+ if err := writeScript(
+ script,
+ `#!/bin/bash
+echo "Running client"
+{{.Bin}} {{.Server}} || exit 101
+echo "Running client again"
+{{.Bin}} {{.Server}} || exit 102
+`,
+ struct{ Bin, Server string }{pingpong, serverName}); err != nil {
+ i.Fatal(err)
+ }
+ client = clientAgent.Start("bash", script)
+ client.Expect("Running client")
+ client.Expect("Pinging...")
+ client.Expect("pong (client:[pingpongd/client] server:[pingpongd])")
+ client.Expect("Running client again")
+ client.Expect("Pinging...")
+ client.Expect("pong (client:[pingpongd/client] server:[pingpongd])")
+ client.WaitOrDie(os.Stdout, os.Stderr)
+ if err := client.Error(); err != nil { // Check expectations
+ i.Fatal(err)
+ }
+}
- agentBin := i.BuildGoPkg("v.io/x/ref/security/agent/agentd")
- testChildBin := i.BuildGoPkg("v.io/x/ref/security/agent/test_child")
- credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
+func V23TestAgentRestartExitCode(i *v23tests.T) {
+ var (
+ clientAgent, serverAgent = createClientAndServerAgents(i)
+ pingpong = i.BuildGoPkg("v.io/x/ref/security/agent/pingpong").Path()
+ serverName = serverAgent.Start(pingpong).ExpectVar("NAME")
- // Test running a single app.
- pingpongBin := buildAndRunPingpongServer(i, rootMTArg)
- pingpongClient := agentBin.WithEnv(credentials).Start(pingpongBin.Path(), rootMTArg)
- // Enter a newline for an empty passphrase to the agent.
- fmt.Fprintln(pingpongClient.Stdin())
- pingpongClient.ReadLine()
- pingpongClient.ExpectRE(".*Pinging...", -1)
- pingpongClient.Expect("pong")
+ scriptDir = i.NewTempDir()
+ counter = filepath.Join(scriptDir, "counter")
+ script = filepath.Join(scriptDir, "test.sh")
+ )
+ if err := writeScript(
+ script,
+ `#!/bin/bash
+# Execute the client ping once
+{{.Bin}} {{.Server}} || exit 101
+# Increment the contents of the counter file
+readonly COUNT=$(expr $(<"{{.Counter}}") + 1)
+echo -n $COUNT >{{.Counter}}
+# Exit code is 0 if the counter is less than 5
+[[ $COUNT -lt 5 ]]; exit $?
+`,
+ struct{ Bin, Server, Counter string }{
+ Bin: pingpong,
+ Server: serverName,
+ Counter: counter,
+ }); err != nil {
+ i.Fatal(err)
+ }
- // Make sure that the agent does not pass VEYRON_CREDENTIALS on to its children
- agent := agentBin.WithEnv(credentials).Start("bash", "-c", "echo", "$VEYRON_CREDENTIALS")
- fmt.Fprintln(agent.Stdin())
- all, err := agent.ReadAll()
+ tests := []struct {
+ RestartExitCode string
+ WantError string
+ WantCounter string
+ }{
+ {
+ // With --restart_exit_code=0, the script should be kicked off
+ // 5 times till the counter reaches 5 and the last iteration of
+ // the script will exit.
+ RestartExitCode: "0",
+ WantError: "exit status 1",
+ WantCounter: "5",
+ },
+ {
+ // With --restart_exit_code=!0, the script will be executed only once.
+ RestartExitCode: "!0",
+ WantError: "",
+ WantCounter: "1",
+ },
+ {
+ // --restart_exit_code=!1, should be the same
+ // as --restart_exit_code=0 for this
+ // particular script only exits with 0 or 1
+ RestartExitCode: "!1",
+ WantError: "exit status 1",
+ WantCounter: "5",
+ },
+ }
+ for _, test := range tests {
+ // Clear out the counter file.
+ if err := ioutil.WriteFile(counter, []byte("0"), 0644); err != nil {
+ i.Fatalf("%q: %v", counter, err)
+ }
+ // Run the script under the agent
+ var gotError string
+ if err := clientAgent.Start(
+ "--restart_exit_code="+test.RestartExitCode,
+ "bash", "-c", script).
+ Wait(os.Stdout, os.Stderr); err != nil {
+ gotError = err.Error()
+ }
+ if got, want := gotError, test.WantError; got != want {
+ i.Errorf("%+v: Got %q, want %q", test, got, want)
+ }
+ if buf, err := ioutil.ReadFile(counter); err != nil {
+ i.Errorf("ioutil.ReadFile(%q) failed: %v", counter, err)
+ } else if got, want := string(buf), test.WantCounter; got != want {
+ i.Errorf("%+v: Got %q, want %q", test, got, want)
+ }
+ }
+}
+
+func writeScript(dstfile, tmpl string, args interface{}) error {
+ t, err := template.New(dstfile).Parse(tmpl)
+ if err != nil {
+ return err
+ }
+ var buf bytes.Buffer
+ if err := t.Execute(&buf, args); err != nil {
+ return err
+ }
+ if err := ioutil.WriteFile(dstfile, buf.Bytes(), 0700); err != nil {
+ return err
+ }
+ return nil
+}
+
+// createClientAndServerAgents creates two principals, sets up their
+// blessings and returns the agent binaries that will use the created credentials.
+//
+// The server will have a single blessing "pingpongd".
+// The client will have a single blessing "pingpongd/client", blessed by the server.
+func createClientAndServerAgents(i *v23tests.T) (client, server *v23tests.Binary) {
+ var (
+ agentd = i.BuildGoPkg("v.io/x/ref/security/agent/agentd")
+ clientDir = i.NewTempDir()
+ serverDir = i.NewTempDir()
+ )
+ pserver, err := vsecurity.CreatePersistentPrincipal(serverDir, nil)
if err != nil {
i.Fatal(err)
}
- if got, want := all, "\n"; got != want {
- i.Fatalf("got %q: VEYRON_CREDENTIALS should not be set when running under the agent", got)
+ pclient, err := vsecurity.CreatePersistentPrincipal(clientDir, nil)
+ if err != nil {
+ i.Fatal(err)
}
-
- // Test running multiple apps connecting to the same agent, we do that using
- // the test_child helper binary which runs the pingpong server and client
- // and has them talk to each other.
- args := []string{testChildBin.Path(), "--rootmt", rootMT, "--pingpong", pingpongBin.Path()}
- testChild := agentBin.WithEnv(credentials).Start(args...)
- // Enter a newline for an empty passphrase to the agent.
- fmt.Fprintln(pingpongClient.Stdin())
-
- testChild.Expect("running client")
- testChild.Expect("client output")
- testChild.ExpectRE(".*Pinging...", -1)
- testChild.Expect("pong")
- testChild.WaitOrDie(nil, nil)
-}
-
-func V23TestAgentRestart(i *v23tests.T) {
- v23tests.RunRootMT(i, "--veyron.tcp.address=127.0.0.1:0")
- ns, _ := i.GetVar("NAMESPACE_ROOT")
-
- // The agent doesn't pass NAMESPACE_ROOT or other env vars through to its
- // children, so we have to pass them specifically to the commands
- // we ask it to run.
-
- rootMTArg := "--veyron.namespace.root=" + ns
-
- agentBin := i.BuildGoPkg("v.io/x/ref/security/agent/agentd")
- vrun := i.BuildGoPkg("v.io/x/ref/cmd/vrun")
-
- pingpongBin := buildAndRunPingpongServer(i, rootMTArg)
- credentials := "VEYRON_CREDENTIALS=" + i.NewTempDir()
-
- // This script increments a counter in $COUNTER_FILE and exits with exit code 0
- // while the counter is < 5, and 1 otherwise.
- counterFile := i.NewTempFile()
-
- script := fmt.Sprintf("%q %q|| exit 101\n", pingpongBin.Path(), rootMTArg)
- script += fmt.Sprintf("%q %q %q|| exit 102\n", vrun.Path(), pingpongBin.Path(), rootMTArg)
- script += fmt.Sprintf("readonly COUNT=$(expr $(<%q) + 1)\n", counterFile.Name())
- script += fmt.Sprintf("echo $COUNT > %q\n", counterFile.Name())
- script += fmt.Sprintf("[[ $COUNT -lt 5 ]]; exit $?\n")
-
- runscript := func(status, exit, counter string) {
- _, file, line, _ := runtime.Caller(1)
- loc := fmt.Sprintf("%s:%d", filepath.Base(file), line)
- i.Logf(exit)
- counterFile.Seek(0, 0)
- fmt.Fprintln(counterFile, "0")
- agent := agentBin.WithEnv(credentials).Start("--additional_principals", i.NewTempDir(), exit, "bash", "-c", script)
- if err := agent.Wait(nil, nil); err == nil {
- if len(status) > 0 {
- i.Fatalf("%s: expected an error %q that didn't occur", loc, status)
- }
- } else {
- if got, want := err.Error(), status; got != want {
- i.Fatalf("%s: got %q, want %q", loc, got, want)
- }
- }
- buf, err := ioutil.ReadFile(counterFile.Name())
- if err != nil {
- i.Fatal(err)
- }
- if got, want := string(buf), counter; got != want {
- i.Fatalf("%s: got %q, want %q", loc, got, want)
- }
+ // Server will only serve, not make any client requests, so only needs a default blessing.
+ bserver, err := pserver.BlessSelf("pingpongd")
+ if err != nil {
+ i.Fatal(err)
}
- runscript("exit status 1", "--restart_exit_code=0", "5\n")
- runscript("", "--restart_exit_code=!0", "1\n")
- runscript("exit status 1", "--restart_exit_code=!1", "5\n")
+ if err := pserver.BlessingStore().SetDefault(bserver); err != nil {
+ i.Fatal(err)
+ }
+ // Clients need not have a default blessing as they will only make a request to the server.
+ bclient, err := pserver.Bless(pclient.PublicKey(), bserver, "client", security.UnconstrainedUse())
+ if err != nil {
+ i.Fatal(err)
+ }
+ if _, err := pclient.BlessingStore().Set(bclient, "pingpongd"); err != nil {
+ i.Fatal(err)
+ }
+ // The client and server must both recognize bserver and its delegates.
+ if err := pserver.AddToRoots(bserver); err != nil {
+ i.Fatal(err)
+ }
+ if err := pclient.AddToRoots(bserver); err != nil {
+ i.Fatal(err)
+ }
+ // TODO(ashankar,ribrdb,suharshs): This should not be needed. It seems
+ // however, that not providing it messes up the agent: Specifically,
+ // the child process is unable to connect to the agent?
+ if err := pclient.BlessingStore().SetDefault(bclient); err != nil {
+ i.Fatal(err)
+ }
+ const envvar = "VEYRON_CREDENTIALS="
+ return agentd.WithEnv(envvar + clientDir), agentd.WithEnv(envvar + serverDir)
}
diff --git a/security/agent/pingpong/main.go b/security/agent/pingpong/main.go
index bc0b2e1..fdcb45b 100644
--- a/security/agent/pingpong/main.go
+++ b/security/agent/pingpong/main.go
@@ -7,28 +7,24 @@
"v.io/v23"
"v.io/v23/context"
"v.io/v23/ipc"
- "v.io/v23/options"
"v.io/v23/security"
"v.io/x/lib/vlog"
"v.io/x/ref/lib/signals"
_ "v.io/x/ref/profiles"
- "v.io/x/ref/test"
)
-var runServer = flag.Bool("server", false, "Whether to run in server mode")
-
type pongd struct{}
-func (f *pongd) Ping(_ ipc.ServerCall, message string) (result string, err error) {
- return "pong", nil
+func (f *pongd) Ping(call ipc.ServerCall, message string) (result string, err error) {
+ client, _ := security.BlessingNames(call, security.CallSideRemote)
+ server, _ := security.BlessingNames(call, security.CallSideLocal)
+ return fmt.Sprintf("pong (client:%v server:%v)", client, server), nil
}
-func clientMain(ctx *context.T) {
+func clientMain(ctx *context.T, server string) {
fmt.Println("Pinging...")
-
- s := PingPongClient("pingpong")
- pong, err := s.Ping(ctx, "ping", options.SkipResolveAuthorization{})
+ pong, err := PingPongClient(server).Ping(ctx, "ping")
if err != nil {
vlog.Fatal("error pinging: ", err)
}
@@ -41,17 +37,18 @@
vlog.Fatal("failure creating server: ", err)
}
vlog.Info("Waiting for ping")
-
- serverPong := PingPongServer(&pongd{})
-
spec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
- if endpoint, err := s.Listen(spec); err == nil {
- fmt.Printf("Listening at: %v\n", endpoint)
+ if endpoints, err := s.Listen(spec); err == nil {
+ fmt.Printf("NAME=%v\n", endpoints[0].Name())
} else {
- vlog.Fatal("error listening to service: ", err)
+ vlog.Fatal("error listening to service:", err)
}
-
- if err := s.Serve("pingpong", serverPong, allowEveryone{}); err != nil {
+ // Provide an empty name, no need to mount on any mounttable.
+ //
+ // Use the default authorization policy (nil authorizer), which will
+ // only authorize clients if the blessings of the client is a prefix of
+ // that of the server or vice-versa.
+ if err := s.Serve("", PingPongServer(&pongd{}), nil); err != nil {
vlog.Fatal("error serving service: ", err)
}
@@ -59,17 +56,15 @@
<-signals.ShutdownOnSignals(ctx)
}
-type allowEveryone struct{}
-
-func (allowEveryone) Authorize(security.Call) error { return nil }
-
func main() {
- ctx, shutdown := test.InitForTest()
+ ctx, shutdown := v23.Init()
defer shutdown()
- if *runServer {
+ if len(flag.Args()) == 0 {
serverMain(ctx)
+ } else if len(flag.Args()) == 1 {
+ clientMain(ctx, flag.Args()[0])
} else {
- clientMain(ctx)
+ vlog.Fatalf("Expected at most one argument, the object name of the server. Got %v", flag.Args())
}
}
diff --git a/security/agent/test_child/main.go b/security/agent/test_child/main.go
deleted file mode 100644
index 3a1e41b..0000000
--- a/security/agent/test_child/main.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// test_child is a helper package for testing two binaries under the same agent.
-package main
-
-import (
- "flag"
- "fmt"
- "os"
- "os/exec"
- "syscall"
-
- "v.io/x/ref/lib/flags/consts"
-)
-
-var (
- pingpong, rootMT string
-)
-
-func init() {
- flag.StringVar(&rootMT, "rootmt", "", "name for the root mounttable")
- flag.StringVar(&pingpong, "pingpong", "", "path name to pingpong binary")
-}
-
-func main() {
- flag.Parse()
- if os.Getenv(consts.VeyronCredentials) != "" {
- panic("VEYRON_CREDENTIALS is set - identity preserved.")
- }
- if len(rootMT) == 0 {
- panic("no rootmt parameter")
- }
- fmt.Fprintf(os.Stderr, "NS ROOT: %v\n\n", os.Getenv(consts.NamespaceRootPrefix))
-
- if len(pingpong) == 0 {
- panic("no pingpong binary supplied")
- }
- ns := consts.NamespaceRootPrefix + "=" + rootMT
- server := exec.Command(pingpong, "--server")
- server.Env = append(server.Env, ns)
- client := exec.Command(pingpong)
- client.Env = append(client.Env, ns)
-
- err := server.Start()
- if err != nil {
- panic(fmt.Sprintf("failed to start server: %s", err))
- }
- defer func() {
- syscall.Kill(server.Process.Pid, syscall.SIGTERM)
- if err = server.Wait(); err != nil {
- panic(fmt.Sprintf("failed to stop server: %s", err))
- }
-
- }()
- fmt.Println("running client")
- output, err := client.Output()
- if err != nil {
- panic(fmt.Sprintf("failed to run client: %s: output: %q", err, output))
- }
- fmt.Println("client output")
- fmt.Println(string(output))
-}
diff --git a/security/agent/test_principal/main.go b/security/agent/test_principal/main.go
index 657c100..2c6bb08 100644
--- a/security/agent/test_principal/main.go
+++ b/security/agent/test_principal/main.go
@@ -12,7 +12,7 @@
"v.io/v23"
"v.io/v23/security"
_ "v.io/x/ref/profiles"
- "v.io/x/ref/test"
+ "v.io/x/ref/security/agent"
)
func newKey() security.PublicKey {
@@ -40,10 +40,25 @@
errors = append(errors, fmt.Sprintf("%v:%d: %v", file, line, fmt.Sprintf(format, args...)))
}
- ctx, shutdown := test.InitForTest()
+ ctx, shutdown := v23.Init()
defer shutdown()
p := v23.GetPrincipal(ctx)
+ // Make sure we're running under a pristine agent to begin with.
+ // The agent aims to be transparent, so use a collection of heuristics
+ // to detect this.
+ if got := os.Getenv("VEYRON_CREDENTIALS"); len(got) != 0 {
+ errorf("VEYRON_CREDENTIALS environment variable is unexpectedly set")
+ }
+ if got := os.Getenv(agent.FdVarName); len(got) == 0 {
+ errorf("%v environment variable is not set", agent.FdVarName)
+ }
+ // A pristine agent has a single blessing "agent_principal" (from agentd/main.go).
+ if blessings := p.BlessingsInfo(p.BlessingStore().Default()); len(blessings) != 1 {
+ errorf("Got %d blessings, expected 1: %v", len(blessings), blessings)
+ } else if _, ok := blessings["agent_principal"]; !ok {
+ errorf("No agent_principal blessins, got %v", blessings)
+ }
// BlessSelf
b, err := p.BlessSelf("batman")
diff --git a/security/agent/v23_test.go b/security/agent/v23_test.go
index 61f3ce8..a6b4044 100644
--- a/security/agent/v23_test.go
+++ b/security/agent/v23_test.go
@@ -45,6 +45,6 @@
v23tests.RunTest(t, V23TestAgentProcesses)
}
-func TestV23AgentRestart(t *testing.T) {
- v23tests.RunTest(t, V23TestAgentRestart)
+func TestV23AgentRestartExitCode(t *testing.T) {
+ v23tests.RunTest(t, V23TestAgentRestartExitCode)
}