blob: d8202f92ed825a7a8a000c9bf916a8f849d0615d [file] [log] [blame]
// 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 rt_test
import (
"fmt"
"io/ioutil"
"os"
"regexp"
"testing"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/security"
"v.io/x/lib/envvar"
"v.io/x/lib/gosh"
"v.io/x/ref"
"v.io/x/ref/internal/logger"
vsecurity "v.io/x/ref/lib/security"
"v.io/x/ref/lib/signals"
"v.io/x/ref/test"
"v.io/x/ref/test/v23test"
)
func TestInit(t *testing.T) {
ref.EnvClearCredentials()
ctx, shutdown := test.V23Init()
defer shutdown()
mgr := logger.Manager(ctx)
fmt.Println(mgr)
args := fmt.Sprintf("%s", mgr)
expected := regexp.MustCompile("name=vanadium logdirs=\\[/tmp\\] logtostderr=true|false alsologtostderr=false|true max_stack_buf_size=4292608 v=[0-9] stderrthreshold=2 vmodule= vfilepath= log_backtrace_at=:0")
if !expected.MatchString(args) {
t.Errorf("unexpected default args: %s, want %s", args, expected)
}
p := v23.GetPrincipal(ctx)
if p == nil {
t.Fatalf("A new principal should have been created")
}
if p.BlessingStore() == nil {
t.Fatalf("The principal must have a BlessingStore")
}
if got, _ := p.BlessingStore().Default(); got.IsZero() {
t.Errorf("Principal().BlessingStore().Default() should not be the zero value")
}
if p.BlessingStore().ForPeer().IsZero() {
t.Errorf("Principal().BlessingStore().ForPeer() should not be the zero value")
}
}
var child = gosh.RegisterFunc("child", func() {
ctx, shutdown := test.V23Init()
defer shutdown()
mgr := logger.Manager(ctx)
ctx.Infof("%s\n", mgr)
fmt.Printf("%s\n", mgr)
<-signals.ShutdownOnSignals(ctx)
})
func TestInitArgs(t *testing.T) {
sh := v23test.NewShell(t, nil)
defer sh.Cleanup()
c := sh.FuncCmd(child)
c.Args = append(c.Args, "--logtostderr=true", "--vmodule=*=3", "--", "foobar")
c.PropagateOutput = true
c.Start()
c.S.Expect(fmt.Sprintf("name=vlog "+
"logdirs=[%s] "+
"logtostderr=true "+
"alsologtostderr=true "+
"max_stack_buf_size=4292608 "+
"v=0 "+
"stderrthreshold=2 "+
"vmodule=*=3 "+
"vfilepath= "+
"log_backtrace_at=:0",
os.TempDir()))
c.Terminate(os.Interrupt)
c.S.ExpectEOF()
}
func validatePrincipal(p security.Principal) error {
if p == nil {
return fmt.Errorf("nil principal")
}
remote, _ := p.BlessingStore().Default()
call := security.NewCall(&security.CallParams{LocalPrincipal: p, RemoteBlessings: remote})
ctx, cancel := context.RootContext()
defer cancel()
blessings, rejected := security.RemoteBlessingNames(ctx, call)
if n := len(blessings); n != 1 {
return fmt.Errorf("rt.Principal().BlessingStore().Default() return blessings:%v (rejected:%v), want exactly one recognized blessing", blessings, rejected)
}
return nil
}
func defaultBlessing(p security.Principal) string {
remote, _ := p.BlessingStore().Default()
call := security.NewCall(&security.CallParams{LocalPrincipal: p, RemoteBlessings: remote})
ctx, cancel := context.RootContext()
defer cancel()
b, _ := security.RemoteBlessingNames(ctx, call)
return b[0]
}
func tmpDir(t *testing.T) string {
dir, err := ioutil.TempDir("", "rt_test_dir")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
return dir
}
var principal = gosh.RegisterFunc("principal", func() error {
ctx, shutdown := test.V23Init()
defer shutdown()
p := v23.GetPrincipal(ctx)
if err := validatePrincipal(p); err != nil {
return err
}
fmt.Printf("DEFAULT_BLESSING=%s\n", defaultBlessing(p))
return nil
})
// Runner runs 'principal' in a subprocess, then reports back with its own
// security info as well as its child's.
var runner = gosh.RegisterFunc("runner", func() error {
ctx, shutdown := test.V23Init()
defer shutdown()
sh := v23test.NewShell(nil, ctx)
defer sh.Cleanup()
p := v23.GetPrincipal(sh.Ctx)
if err := validatePrincipal(p); err != nil {
return err
}
fmt.Printf("RUNNER_DEFAULT_BLESSING=%v\n", defaultBlessing(p))
c := sh.FuncCmd(principal)
// Make sure the child gets its credentials from this shell (via agent), not
// from the original EnvCredentials env var.
delete(c.Vars, ref.EnvCredentials)
c.PropagateOutput = true
c.Run()
return nil
})
func createCredentialsInDir(t *testing.T, dir string, blessing string) {
principal, err := vsecurity.CreatePersistentPrincipal(dir, nil)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if err := vsecurity.InitDefaultBlessings(principal, blessing); err != nil {
t.Fatalf("unexpected error: %s", err)
}
}
func TestPrincipalInheritance(t *testing.T) {
sh := v23test.NewShell(t, nil)
defer sh.Cleanup()
// Test that the child inherits from the parent's credentials correctly.
// The running test process may or may not have a credentials directory set
// up, so we have to use a 'runner' process to ensure the correct setup.
cdir := tmpDir(t)
defer os.RemoveAll(cdir)
createCredentialsInDir(t, cdir, "test")
// Directory supplied by the environment.
c := sh.FuncCmd(runner)
c.Vars[ref.EnvCredentials] = cdir
c.Start()
runnerBlessing := c.S.ExpectVar("RUNNER_DEFAULT_BLESSING")
principalBlessing := c.S.ExpectVar("DEFAULT_BLESSING")
if err := c.S.Error(); err != nil {
t.Fatalf("failed to read input from children: %s", err)
}
c.Wait()
wantRunnerBlessing := "test"
wantPrincipalBlessing := "test:child"
if runnerBlessing != wantRunnerBlessing || principalBlessing != wantPrincipalBlessing {
t.Fatalf("unexpected default blessing: got runner %s, principal %s, want runner %s, principal %s", runnerBlessing, principalBlessing, wantRunnerBlessing, wantPrincipalBlessing)
}
}
func TestPrincipalInit(t *testing.T) {
// Runs the principal function and returns the child's default blessing.
collect := func(sh *v23test.Shell, extraVars map[string]string, extraArgs ...string) string {
c := sh.FuncCmd(principal)
c.Vars = envvar.MergeMaps(c.Vars, extraVars)
c.Args = append(c.Args, extraArgs...)
c.Start()
return c.S.ExpectVar("DEFAULT_BLESSING")
}
// Set aside any credentials dir specified via env.
origEnvCredentials := os.Getenv(ref.EnvCredentials)
defer os.Setenv(ref.EnvCredentials, origEnvCredentials)
if err := os.Unsetenv(ref.EnvCredentials); err != nil {
t.Fatal(err)
}
// Note, v23test.Shell uses the agent to pass credentials to its children.
sh := v23test.NewShell(t, nil)
defer sh.Cleanup()
// Test that the shell uses the EnvAgentPath, not EnvCredentials, to pass
// credentials to its children.
c := sh.FuncCmd(principal)
if _, ok := c.Vars[ref.EnvCredentials]; ok {
t.Fatal("Did not expect child to have EnvCredentials set")
}
if _, ok := c.Vars[ref.EnvAgentPath]; !ok {
t.Fatal("Expected child to have EnvAgentPath set")
}
// Test that with ref.EnvCredentials unset, the child runtime's principal is
// initialized as expected.
if got, want := collect(sh, nil), "root:child"; got != want {
t.Fatalf("got %q, want %q", got, want)
}
// Test that credentials specified via the ref.EnvCredentials environment
// variable take precedence over credentials from ref.EnvAgentPath.
cdir1 := tmpDir(t)
defer os.RemoveAll(cdir1)
createCredentialsInDir(t, cdir1, "test_env")
credEnv := map[string]string{ref.EnvCredentials: cdir1}
if got, want := collect(sh, credEnv), "test_env"; got != want {
t.Errorf("got %q, want %q", got, want)
}
// Test that credentials specified via the command line (--v23.credentials)
// take precedence over the ref.EnvCredentials and ref.EnvAgentPath
// environment variables.
cdir2 := tmpDir(t)
defer os.RemoveAll(cdir2)
createCredentialsInDir(t, cdir2, "test_cmd")
if got, want := collect(sh, credEnv, "--v23.credentials="+cdir2), "test_cmd"; got != want {
t.Errorf("got %q, want %q", got, want)
}
}