"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.