"veyron/lib/testutil/security": ForkCredentials

In order to make it easy for tests to setup credentials for various
processes or runtimes that they start, this CL defines two methods
in the testutil/security package:
1) NewCredentials(names): Returns a new Veyron credentials
directory with a principal that has self-signed blessings for 'names'.
2) ForkCredentials(parent, extensions): Returns a new Veyron
credentials directory with a principal that is blessed by 'parent'
under 'extensions'.

Change-Id: I999e0fc0f598574463a66bd0a0023e346f347345
diff --git a/lib/modules/modules_test.go b/lib/modules/modules_test.go
index 074d39a..c8512eb 100644
--- a/lib/modules/modules_test.go
+++ b/lib/modules/modules_test.go
@@ -430,10 +430,9 @@
 	sh.Cleanup(nil, nil)
 
 	// Test child credentials when VeyronCredentials are set.
-	root := tsecurity.NewPrincipal("root")
 	old := os.Getenv(consts.VeyronCredentials)
 	defer os.Setenv(consts.VeyronCredentials, old)
-	dir := tsecurity.NewVeyronCredentials(root, "os")
+	dir, _ := tsecurity.NewCredentials("os")
 	defer os.RemoveAll(dir)
 	if err := os.Setenv(consts.VeyronCredentials, dir); err != nil {
 		t.Fatal(err)
@@ -442,7 +441,7 @@
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "root/os/child"); err != nil {
+	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "os/child"); err != nil {
 		t.Fatal(err)
 	}
 	sh.Cleanup(nil, nil)
@@ -453,34 +452,34 @@
 	}
 
 	// Test that VeyronCredentials specified on the shell override the OS ones.
-	dir = tsecurity.NewVeyronCredentials(root, "shell")
+	dir, _ = tsecurity.NewCredentials("shell")
 	defer os.RemoveAll(dir)
 	sh, err = modules.NewShell(nil)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
 	sh.SetVar(consts.VeyronCredentials, dir)
-	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "root/shell/child"); err != nil {
+	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "shell/child"); err != nil {
 		t.Fatal(err)
 	}
 	sh.ClearVar(consts.VeyronCredentials)
 	if credentials := startChildAndGetCredentials(sh, nil); len(credentials) != 0 {
 		t.Fatalf("found credentials %v set for child even when shell credentials were cleared", credentials)
 	}
-	anotherDir := tsecurity.NewVeyronCredentials(root, "anotherShell")
+	anotherDir, _ := tsecurity.NewCredentials("anotherShell")
 	defer os.RemoveAll(anotherDir)
 	sh.SetVar(consts.VeyronCredentials, anotherDir)
-	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "root/anotherShell/child"); err != nil {
+	if err := validateCredentials(startChildAndGetCredentials(sh, nil), "anotherShell/child"); err != nil {
 		t.Fatal(err)
 	}
 	sh.Cleanup(nil, nil)
 
 	// Test that VeyronCredentials specified as a parameter overrides the OS and
 	// shell ones.
-	dir = tsecurity.NewVeyronCredentials(root, "param")
+	dir, _ = tsecurity.NewCredentials("param")
 	defer os.RemoveAll(dir)
 	env := []string{consts.VeyronCredentials + "=" + dir}
-	if err := validateCredentials(startChildAndGetCredentials(sh, env), "root/param"); err != nil {
+	if err := validateCredentials(startChildAndGetCredentials(sh, env), "param"); err != nil {
 		t.Fatal(err)
 	}
 
diff --git a/lib/signals/signals_test.go b/lib/signals/signals_test.go
index 198f830..693e425 100644
--- a/lib/signals/signals_test.go
+++ b/lib/signals/signals_test.go
@@ -350,7 +350,7 @@
 
 	// Set the child process up with a blessing from the parent so that
 	// the default authorization works for RPCs between the two.
-	childcreds := security.NewVeyronCredentials(runtime.Principal(), "child")
+	childcreds, _ := security.ForkCredentials(runtime.Principal(), "child")
 	defer os.RemoveAll(childcreds)
 	configServer, configServiceName, ch := createConfigServer(t, runtime)
 	defer configServer.Stop()
diff --git a/lib/testutil/security/util.go b/lib/testutil/security/util.go
index a696269..40a7279 100644
--- a/lib/testutil/security/util.go
+++ b/lib/testutil/security/util.go
@@ -1,5 +1,25 @@
 // Package security contains utility testing functions related to
-// security.
+// veyron2/security.
+//
+// Suggested Usage:
+//
+// Create a new in-memory principal with an empty BlessingStore.
+// p := NewPrincipal()
+//
+// Create a new in-memory principal with self-signed blessing for "alice".
+// p := NewPrincipal("alice")
+//
+// Create a VeyronCredentials directory with a new persistent principal that has a
+// self-signed blessing for "alice"  -- this directory can be set as the value
+// of the VEYRON_CREDENTIALS environment variable or the --veyron.credentials flag
+// used to initialize a runtime. All updates to the principal's state get subsequently
+// persisted to the directory. Both the directory and a handle to the created principal
+// are returned.
+// dir, p := NewCredentials("alice")  // principal p has blessing "alice"
+//
+// Create a VeyronCredentials directory with a new persistent principal that is
+// blessed by the principal p under the extension "friend"
+// forkdir, forkp := ForkCredentials(p, "friend")  // principal forkp has blessing "alice/friend"
 package security
 
 import (
@@ -12,31 +32,85 @@
 	"veyron.io/veyron/veyron2/services/security/access"
 )
 
-// NewVeyronCredentials generates a directory with a new principal
-// that can be used as a value for the VEYRON_CREDENTIALS environment
-// variable to initialize a Runtime.
-//
-// The principal created uses a blessing from 'parent', with the extension
-// 'name' as its default blessing.
-//
-// It returns the path to the directory created.
-func NewVeyronCredentials(parent security.Principal, name string) string {
+func newCredentials() (string, security.Principal) {
 	dir, err := ioutil.TempDir("", "veyron_credentials")
 	if err != nil {
 		panic(err)
 	}
-	p, err := vsecurity.LoadPersistentPrincipal(dir, nil)
-	if err != nil {
-		if p, err = vsecurity.CreatePersistentPrincipal(dir, nil); err != nil {
-			panic(err)
-		}
-	}
-	blessings, err := parent.Bless(p.PublicKey(), parent.BlessingStore().Default(), name, security.UnconstrainedUse())
+	p, err := vsecurity.CreatePersistentPrincipal(dir, nil)
 	if err != nil {
 		panic(err)
 	}
-	SetDefaultBlessings(p, blessings)
-	return dir
+	return dir, p
+}
+
+func selfBlessings(p security.Principal, names ...string) security.Blessings {
+	var blessings security.Blessings
+	for _, name := range names {
+		b, err := p.BlessSelf(name)
+		if err != nil {
+			panic(err)
+		}
+		if blessings, err = security.UnionOfBlessings(blessings, b); err != nil {
+			panic(err)
+		}
+	}
+	return blessings
+}
+
+// NewCredentials generates a directory with a new principal with
+// self-signed blessings.
+//
+// In particular, the principal is initialized with self-signed
+// blessings for the provided 'names', marked as  default and shareable
+// with all peers on the principal's blessing store.
+//
+// It returns the path to the directory created and the principal.
+// The directory can be used as a value for the VEYRON_CREDENTIALS
+// environment variable (or the --veyron.credentials flag) used to
+// initialize a Runtime.
+func NewCredentials(requiredName string, otherNames ...string) (string, security.Principal) {
+	dir, p := newCredentials()
+	if def := selfBlessings(p, append([]string{requiredName}, otherNames...)...); def != nil {
+		SetDefaultBlessings(p, def)
+	}
+	return dir, p
+}
+
+// ForkCredentials generates a directory with a new principal whose
+// blessings are provided by the 'parent'.
+//
+// In particular, the principal is initialized with blessings from
+// 'parent' under the provided 'extensions', and marked as default and
+// shareable with all peers on the principal's blessing store.
+//
+// It returns the path to the directory created and the principal.
+// The directory can be used as a value for the VEYRON_CREDENTIALS
+// environment variable (or the --veyron.credentials flag) used to
+// initialize a Runtime.
+func ForkCredentials(parent security.Principal, requiredExtension string, otherExtensions ...string) (string, security.Principal) {
+	dir, err := ioutil.TempDir("", "veyron_credentials")
+	if err != nil {
+		panic(err)
+	}
+	p, err := vsecurity.CreatePersistentPrincipal(dir, nil)
+	if err != nil {
+		panic(err)
+	}
+	var def security.Blessings
+	for _, extension := range append([]string{requiredExtension}, otherExtensions...) {
+		b, err := parent.Bless(p.PublicKey(), parent.BlessingStore().Default(), extension, security.UnconstrainedUse())
+		if err != nil {
+			panic(err)
+		}
+		if def, err = security.UnionOfBlessings(def, b); err != nil {
+			panic(err)
+		}
+	}
+	if def != nil {
+		SetDefaultBlessings(p, def)
+	}
+	return dir, p
 }
 
 // NewPrincipal creates a new security.Principal.
@@ -49,17 +123,7 @@
 	if err != nil {
 		panic(err)
 	}
-	var def security.Blessings
-	for _, blessing := range defaultBlessings {
-		b, err := p.BlessSelf(blessing)
-		if err != nil {
-			panic(err)
-		}
-		if def, err = security.UnionOfBlessings(def, b); err != nil {
-			panic(err)
-		}
-	}
-	if def != nil {
+	if def := selfBlessings(p, defaultBlessings...); def != nil {
 		SetDefaultBlessings(p, def)
 	}
 	return p
diff --git a/lib/testutil/security/util_test.go b/lib/testutil/security/util_test.go
index 8b3070a..67bf51e 100644
--- a/lib/testutil/security/util_test.go
+++ b/lib/testutil/security/util_test.go
@@ -1,8 +1,10 @@
 package security
 
 import (
+	"fmt"
 	"os"
 	"reflect"
+	"sort"
 	"testing"
 
 	"veyron.io/veyron/veyron2/rt"
@@ -13,24 +15,50 @@
 	vsecurity "veyron.io/veyron/veyron/security"
 )
 
-func TestNewVeyronCredentials(t *testing.T) {
-	r, err := rt.New()
+func unsortedEquals(a, b []string) bool {
+	sort.Strings(a)
+	sort.Strings(b)
+	return reflect.DeepEqual(a, b)
+}
+
+func testCredentials(cred string, wantPrincipal security.Principal, wantBlessings []string) error {
+	pFromCred, err := vsecurity.LoadPersistentPrincipal(cred, nil)
 	if err != nil {
+		return fmt.Errorf("LoadPersistentPrincipal(%q, nil) failed: %v", cred, err)
+	}
+	if !reflect.DeepEqual(pFromCred, wantPrincipal) {
+		fmt.Errorf("got principal from directory: %v, want: %v", pFromCred, wantPrincipal)
+	}
+
+	// TODO(ashankar,ataly): Extract blessings using the principal.BlessingInfo API
+	// instead of blessings.ForContext.
+	ctx := security.NewContext(&security.ContextParams{
+		LocalPrincipal: pFromCred,
+	})
+	if got := pFromCred.BlessingStore().ForPeer("foo").ForContext(ctx); !unsortedEquals(got, wantBlessings) {
+		return fmt.Errorf("got peer blessings: %v, want: %v", got, wantBlessings)
+	}
+	if got := pFromCred.BlessingStore().Default().ForContext(ctx); !unsortedEquals(got, wantBlessings) {
+		return fmt.Errorf("got default blessings: %v, want: %v", got, wantBlessings)
+	}
+	return nil
+}
+
+func TestCredentials(t *testing.T) {
+	dir, p := NewCredentials("ali", "alice")
+	if err := testCredentials(dir, p, []string{"ali", "alice"}); err != nil {
 		t.Fatal(err)
 	}
-	defer r.Cleanup()
 
-	parent := r.Principal()
-	childdir := NewVeyronCredentials(parent, "child")
-	defer os.RemoveAll(childdir)
-	if _, err = vsecurity.LoadPersistentPrincipal(childdir, nil); err != nil {
-		t.Fatalf("Expected NewVeyronCredentials to have populated the directory %q: %v", childdir, err)
+	forkdir, forkp := ForkCredentials(p, "friend", "enemy")
+	if err := testCredentials(forkdir, forkp, []string{"ali/friend", "alice/friend", "ali/enemy", "alice/enemy"}); err != nil {
+		t.Fatal(err)
 	}
-	// TODO(ashankar,ataly): Figure out what APIs should we use for more detailed testing
-	// of the child principal, for example:
-	// - Parent should recognize the child's default blessing
-	// - Child should recognize the parent's default blessing
-	// - Child's blessing name should be that of the parent with "/child" appended.
+
+	forkforkdir, forkforkp := ForkCredentials(forkp, "spouse")
+	if err := testCredentials(forkforkdir, forkforkp, []string{"ali/friend/spouse", "alice/friend/spouse", "ali/enemy/spouse", "alice/enemy/spouse"}); err != nil {
+		t.Fatal(err)
+	}
 }
 
 func TestSaveACLToFile(t *testing.T) {
diff --git a/runtimes/google/rt/mgmt_test.go b/runtimes/google/rt/mgmt_test.go
index a43c2d7..fd59c0a 100644
--- a/runtimes/google/rt/mgmt_test.go
+++ b/runtimes/google/rt/mgmt_test.go
@@ -295,7 +295,7 @@
 func setupRemoteAppCycleMgr(t *testing.T) (veyron2.Runtime, modules.Handle, appcycle.AppCycleClientMethods, func()) {
 	r, _ := rt.New(profileOpt)
 
-	childcreds := security.NewVeyronCredentials(r.Principal(), appCmd)
+	childcreds, _ := security.ForkCredentials(r.Principal(), appCmd)
 	configServer, configServiceName, ch := createConfigServer(t, r)
 	sh, err := modules.NewShell(nil)
 	if err != nil {
diff --git a/services/mgmt/application/applicationd/testdata/integration_test.go b/services/mgmt/application/applicationd/testdata/integration_test.go
index 2c68229..4a66a8e 100644
--- a/services/mgmt/application/applicationd/testdata/integration_test.go
+++ b/services/mgmt/application/applicationd/testdata/integration_test.go
@@ -75,10 +75,9 @@
 	defer handle.CloseStdin()
 
 	// Generate credentials.
-	root := security.NewPrincipal("root")
-	serverCred := security.NewVeyronCredentials(root, "server")
+	serverCred, serverPrin := security.NewCredentials("server")
 	defer os.RemoveAll(serverCred)
-	clientCred := security.NewVeyronCredentials(root, "server/client")
+	clientCred, _ := security.ForkCredentials(serverPrin, "client")
 	defer os.RemoveAll(clientCred)
 
 	// Start the application repository.
diff --git a/services/mgmt/binary/binaryd/testdata/integration_test.go b/services/mgmt/binary/binaryd/testdata/integration_test.go
index b69c2bf..d28b3cb 100644
--- a/services/mgmt/binary/binaryd/testdata/integration_test.go
+++ b/services/mgmt/binary/binaryd/testdata/integration_test.go
@@ -150,10 +150,9 @@
 	defer handle.CloseStdin()
 
 	// Generate credentials.
-	rootPrin := security.NewPrincipal("root")
-	serverCred := security.NewVeyronCredentials(rootPrin, "server")
+	serverCred, serverPrin := security.NewCredentials("server")
 	defer os.RemoveAll(serverCred)
-	clientCred := security.NewVeyronCredentials(rootPrin, "server/client")
+	clientCred, _ := security.ForkCredentials(serverPrin, "client")
 	defer os.RemoveAll(clientCred)
 
 	// Start the build server.
diff --git a/services/mgmt/build/buildd/testdata/integration_test.go b/services/mgmt/build/buildd/testdata/integration_test.go
index 304f9a0..68bae88 100644
--- a/services/mgmt/build/buildd/testdata/integration_test.go
+++ b/services/mgmt/build/buildd/testdata/integration_test.go
@@ -68,10 +68,9 @@
 	defer handle.CloseStdin()
 
 	// Generate credentials.
-	root := security.NewPrincipal("root")
-	serverCred := security.NewVeyronCredentials(root, "server")
+	serverCred, serverPrin := security.NewCredentials("server")
 	defer os.RemoveAll(serverCred)
-	clientCred := security.NewVeyronCredentials(root, "server/client")
+	clientCred, _ := security.ForkCredentials(serverPrin, "client")
 	defer os.RemoveAll(clientCred)
 
 	// Start the build server.
diff --git a/services/mgmt/device/impl/util_test.go b/services/mgmt/device/impl/util_test.go
index 197453c..4b7f342 100644
--- a/services/mgmt/device/impl/util_test.go
+++ b/services/mgmt/device/impl/util_test.go
@@ -61,7 +61,7 @@
 }
 
 func credentialsForChild(blessing string) (string, []string) {
-	creds := tsecurity.NewVeyronCredentials(globalRT.Principal(), blessing)
+	creds, _ := tsecurity.ForkCredentials(globalRT.Principal(), blessing)
 	return creds, []string{consts.VeyronCredentials + "=" + creds}
 }
 
diff --git a/services/mgmt/profile/profiled/testdata/integration_test.go b/services/mgmt/profile/profiled/testdata/integration_test.go
index 7f9dc53..cd1ba22 100644
--- a/services/mgmt/profile/profiled/testdata/integration_test.go
+++ b/services/mgmt/profile/profiled/testdata/integration_test.go
@@ -96,10 +96,9 @@
 	defer handle.CloseStdin()
 
 	// Generate credentials.
-	root := security.NewPrincipal("root")
-	serverCred := security.NewVeyronCredentials(root, "server")
+	serverCred, serverPrin := security.NewCredentials("server")
 	defer os.RemoveAll(serverCred)
-	clientCred := security.NewVeyronCredentials(root, "server/client")
+	clientCred, _ := security.ForkCredentials(serverPrin, "client")
 	defer os.RemoveAll(clientCred)
 
 	// Start the profile repository.