Merge "veyron/lib/glob: Recursive matches are not exact matches."
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index 96ed5d5..baa2f6b 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -45,14 +45,10 @@
 	"io"
 	"io/ioutil"
 	"os"
-	"path/filepath"
 	"strings"
 	"sync"
 
 	"veyron.io/veyron/veyron2/vlog"
-
-	isecurity "veyron.io/veyron/veyron/runtimes/google/security"
-	seclib "veyron.io/veyron/veyron/security"
 )
 
 // Shell represents the context within which commands are run.
@@ -61,7 +57,7 @@
 	env     map[string]string
 	cmds    map[string]*commandDesc
 	handles map[Handle]struct{}
-	idfile  string
+	credDir string
 }
 
 type commandDesc struct {
@@ -82,9 +78,9 @@
 var child = &childRegistrar{mains: make(map[string]*childEntryPoint)}
 
 // NewShell creates a new instance of Shell. If this new instance is
-// is a test and no identity has been configured in the environment
-// via VEYRON_IDENTITY then CreateAndUseNewID will be used to configure a new
-// ID for the shell and its children.
+// is a test and no credentials have been configured in the environment
+// via VEYRON_CREDENTIALS then CreateAndUseNewCredentials will be used to
+// configure a new ID for the shell and its children.
 // NewShell takes optional regexp patterns that can be used to specify
 // subprocess commands that are implemented in the same binary as this shell
 // (i.e. have been registered using modules.RegisterChild) to be
@@ -98,8 +94,9 @@
 		cmds:    make(map[string]*commandDesc),
 		handles: make(map[Handle]struct{}),
 	}
-	if flag.Lookup("test.run") != nil && os.Getenv("VEYRON_IDENTITY") == "" {
-		if err := sh.CreateAndUseNewID(); err != nil {
+	if flag.Lookup("test.run") != nil && os.Getenv("VEYRON_CREDENTIALS") == "" {
+		if err := sh.CreateAndUseNewCredentials(); err != nil {
+			// TODO(cnicolaou): return an error rather than panic.
 			panic(err)
 		}
 	}
@@ -109,25 +106,15 @@
 	return sh
 }
 
-// CreateAndUseNewID setups a new ID and then configures the shell and all of its
-// children to use to it.
-func (sh *Shell) CreateAndUseNewID() error {
-	id, err := isecurity.NewPrivateID("test", nil)
+// CreateAndUseNewCredentials setups a new credentials directory and then
+// configures the shell and all of its children to use to it.
+func (sh *Shell) CreateAndUseNewCredentials() error {
+	dir, err := ioutil.TempDir("", "veyron_credentials")
 	if err != nil {
 		return err
 	}
-	f, err := ioutil.TempFile("", filepath.Base(os.Args[0]))
-	if err != nil {
-		return err
-	}
-	defer f.Close()
-	filePath := f.Name()
-	if err := seclib.SaveIdentity(f, id); err != nil {
-		os.Remove(filePath)
-		return err
-	}
-	sh.idfile = filePath
-	sh.SetVar("VEYRON_IDENTITY", sh.idfile)
+	sh.credDir = dir
+	sh.SetVar("VEYRON_CREDENTIALS", sh.credDir)
 	return nil
 }
 
@@ -274,8 +261,8 @@
 	for k, _ := range handles {
 		k.Shutdown(stdout, stderr)
 	}
-	if len(sh.idfile) > 0 {
-		os.Remove(sh.idfile)
+	if len(sh.credDir) > 0 {
+		os.RemoveAll(sh.credDir)
 	}
 }
 
diff --git a/lib/netconfig/ipaux_other.go b/lib/netconfig/ipaux_other.go
index 5345a8f..23496f0 100644
--- a/lib/netconfig/ipaux_other.go
+++ b/lib/netconfig/ipaux_other.go
@@ -1,4 +1,4 @@
-// +build plan9 windows nacl
+// +build !linux,!bsd
 // TODO(bprosnitz) Should change for nacl?
 
 package netconfig
diff --git a/lib/signals/signals_test.go b/lib/signals/signals_test.go
index ade0df3..634e1d2 100644
--- a/lib/signals/signals_test.go
+++ b/lib/signals/signals_test.go
@@ -324,22 +324,20 @@
 
 // TestCleanRemoteShutdown verifies that remote shutdown works correctly.
 func TestCleanRemoteShutdown(t *testing.T) {
-	r := rt.Init()
+	r := rt.Init(veyron2.ForceNewSecurityModel{})
 	defer r.Cleanup()
 
 	sh := modules.NewShell()
 	sh.AddSubprocess("handleDefaults", "")
 	defer sh.Cleanup(os.Stderr, os.Stderr)
 
-	// This sets up the child's identity to be derived from the parent's (so
-	// that default authorization works for RPCs between the two).
-	// TODO(caprita): Consider making this boilerplate part of blackbox.
-	id := r.Identity()
-	idFile := security.SaveIdentityToFile(security.NewBlessedIdentity(id, "test"))
-	defer os.Remove(idFile)
+	// 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(r.Principal(), "child")
+	defer os.RemoveAll(childcreds)
 	configServer, configServiceName, ch := createConfigServer(t)
 	defer configServer.Stop()
-	sh.SetVar("VEYRON_IDENTITY", idFile)
+	sh.SetVar("VEYRON_CREDENTIALS", childcreds)
 	sh.SetVar(mgmt.ParentNodeManagerConfigKey, configServiceName)
 	h, err := sh.Start("handleDefaults")
 	if err != nil {
diff --git a/lib/testutil/security/util.go b/lib/testutil/security/util.go
index 9a45b2c..2bf1fdb 100644
--- a/lib/testutil/security/util.go
+++ b/lib/testutil/security/util.go
@@ -5,34 +5,55 @@
 import (
 	"io/ioutil"
 	"os"
-	"strconv"
-	"time"
 
-	"veyron.io/veyron/veyron/lib/testutil"
-	isecurity "veyron.io/veyron/veyron/runtimes/google/security"
 	vsecurity "veyron.io/veyron/veyron/security"
 
 	"veyron.io/veyron/veyron2/security"
 )
 
-// NewBlessedIdentity creates a new identity and blesses it using the provided blesser
-// under the provided name. This function is meant to be used for testing purposes only,
-// it panics if there is an error.
-func NewBlessedIdentity(blesser security.PrivateID, name string) security.PrivateID {
-	id, err := isecurity.NewPrivateID("test", nil)
+// 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 {
+	dir, err := ioutil.TempDir("", "veyron_credentials")
 	if err != nil {
 		panic(err)
 	}
+	p, _, err := vsecurity.NewPersistentPrincipal(dir)
+	if err != nil {
+		panic(err)
+	}
+	blessings, err := parent.Bless(p.PublicKey(), parent.BlessingStore().Default(), name, security.UnconstrainedUse())
+	if err != nil {
+		panic(err)
+	}
+	SetDefaultBlessings(p, blessings)
+	return dir
+}
 
-	blessedID, err := blesser.Bless(id.PublicID(), name, 5*time.Minute, nil)
-	if err != nil {
+// SetDefaultBlessings updates the BlessingStore and BlessingRoots of p
+// so that:
+// (1) b is revealed to all clients that connect to Servers operated
+// by 'p' (BlessingStore.Default)
+// (2) b is revealed  to all servers that clients connect to on behalf
+// of p (BlessingStore.Set(..., security.AllPrincipals))
+// (3) p recognizes all blessings that have the same root certificate as b.
+// (AddToRoots)
+func SetDefaultBlessings(p security.Principal, b security.Blessings) {
+	if err := p.BlessingStore().SetDefault(b); err != nil {
 		panic(err)
 	}
-	derivedID, err := id.Derive(blessedID)
-	if err != nil {
+	if _, err := p.BlessingStore().Set(b, security.AllPrincipals); err != nil {
 		panic(err)
 	}
-	return derivedID
+	if err := p.AddToRoots(b); err != nil {
+		panic(err)
+	}
 }
 
 // SaveACLToFile saves the provided ACL in JSON format to a randomly created
@@ -51,23 +72,3 @@
 	}
 	return f.Name()
 }
-
-// SaveIdentityToFile saves the provided identity in Base64VOM format
-// to a randomly created temporary file, and returns the path to the file.
-// This function is meant to be used for testing purposes only, it panics
-// if there is an error. The caller must ensure that the created file
-// is removed once it is no longer needed.
-func SaveIdentityToFile(id security.PrivateID) string {
-	f, err := ioutil.TempFile("", strconv.Itoa(testutil.Rand.Int()))
-	if err != nil {
-		panic(err)
-	}
-	defer f.Close()
-	filePath := f.Name()
-
-	if err := vsecurity.SaveIdentity(f, id); err != nil {
-		os.Remove(filePath)
-		panic(err)
-	}
-	return filePath
-}
diff --git a/lib/testutil/security/util_test.go b/lib/testutil/security/util_test.go
index 5125d1e..ea9ee21 100644
--- a/lib/testutil/security/util_test.go
+++ b/lib/testutil/security/util_test.go
@@ -1,47 +1,37 @@
 package security
 
 import (
-	"fmt"
 	"os"
 	"reflect"
 	"testing"
 
-	isecurity "veyron.io/veyron/veyron/runtimes/google/security"
 	vsecurity "veyron.io/veyron/veyron/security"
 
 	"veyron.io/veyron/veyron2/rt"
 	"veyron.io/veyron/veyron2/security"
 )
 
-func TestNewBlessedIdentity(t *testing.T) {
+func TestNewVeyronCredentials(t *testing.T) {
 	r, err := rt.New()
 	if err != nil {
-		t.Fatalf("rt.New failed: %v", err)
+		t.Fatal(err)
 	}
 	defer r.Cleanup()
-	newID := func(name string) security.PrivateID {
-		id, err := r.NewIdentity(name)
-		if err != nil {
-			t.Fatalf("r.NewIdentity failed: %v", err)
-		}
-		isecurity.TrustIdentityProviders(id)
-		return id
+
+	parent := r.Principal()
+	childdir := NewVeyronCredentials(parent, "child")
+	_, existed, err := vsecurity.NewPersistentPrincipal(childdir)
+	if err != nil {
+		t.Fatal(err)
 	}
-	testdata := []struct {
-		blesser            security.PrivateID
-		blessingName, name string
-	}{
-		{blesser: newID("google"), blessingName: "alice", name: "PrivateID:google/alice"},
-		{blesser: newID("google"), blessingName: "bob", name: "PrivateID:google/bob"},
-		{blesser: newID("veyron"), blessingName: "alice", name: "PrivateID:veyron/alice"},
-		{blesser: newID("veyron"), blessingName: "bob", name: "PrivateID:veyron/bob"},
-		{blesser: NewBlessedIdentity(newID("google"), "alice"), blessingName: "tv", name: "PrivateID:google/alice/tv"},
+	if !existed {
+		t.Fatalf("Expected NewVeyronCredentials to have populated the directory %q", childdir)
 	}
-	for _, d := range testdata {
-		if got, want := fmt.Sprintf("%s", NewBlessedIdentity(d.blesser, d.blessingName)), d.name; got != want {
-			t.Errorf("NewBlessedIdentity(%q, %q): Got %q, want %q", d.blesser, d.blessingName, got, want)
-		}
-	}
+	// 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.
 }
 
 func TestSaveACLToFile(t *testing.T) {
@@ -76,31 +66,3 @@
 		t.Fatalf("Got ACL %v, but want %v", loadedACL, acl)
 	}
 }
-
-func TestSaveIdentityToFile(t *testing.T) {
-	r, err := rt.New()
-	if err != nil {
-		t.Fatalf("rt.New failed: %v", err)
-	}
-	defer r.Cleanup()
-	id, err := r.NewIdentity("test")
-	if err != nil {
-		t.Fatalf("r.NewIdentity failed: %v", err)
-	}
-
-	filePath := SaveIdentityToFile(id)
-	defer os.Remove(filePath)
-
-	f, err := os.Open(filePath)
-	if err != nil {
-		t.Fatalf("os.Open(%v) failed: %v", filePath, err)
-	}
-	defer f.Close()
-	loadedID, err := vsecurity.LoadIdentity(f)
-	if err != nil {
-		t.Fatalf("LoadIdentity failed: %v", err)
-	}
-	if !reflect.DeepEqual(loadedID, id) {
-		t.Fatalf("Got Identity %v, but want %v", loadedID, id)
-	}
-}
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 610e2a6..ddefad2 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -152,6 +152,8 @@
 			return nil, err
 		}
 	}
+	// TODO(cnicolaou): pass ServesMountTableOpt to streamMgr.Listen so that
+	// it can more cleanly set the IsMountTable bit in the endpoint.
 	ln, ep, err := s.streamMgr.Listen(protocol, address, s.listenerOpts...)
 	if err != nil {
 		vlog.Errorf("ipc: Listen on %v %v failed: %v", protocol, address, err)
@@ -197,18 +199,18 @@
 	// Each flow is served from its own goroutine.
 	s.active.Add(1)
 	if protocol == inaming.Network {
-		go func(ln stream.Listener, ep naming.Endpoint, proxy string) {
+		go func(ln stream.Listener, ep *inaming.Endpoint, proxy string) {
 			s.proxyListenLoop(ln, ep, proxy)
 			s.active.Done()
-		}(ln, ep, proxyName)
+		}(ln, iep, proxyName)
 	} else {
 		go func(ln stream.Listener, ep naming.Endpoint) {
 			s.listenLoop(ln, ep)
 			s.active.Done()
-		}(ln, ep)
+		}(ln, iep)
 	}
 	s.Unlock()
-	s.publisher.AddServer(s.publishEP(ep), s.servesMountTable)
+	s.publisher.AddServer(s.publishEP(iep, s.servesMountTable), s.servesMountTable)
 	return ep, nil
 }
 
@@ -221,7 +223,6 @@
 	if !ok {
 		return nil, nil, fmt.Errorf("failed translating internal endpoint data types")
 	}
-
 	switch iep.Protocol {
 	case "tcp", "tcp4", "tcp6":
 		host, port, err := net.SplitHostPort(iep.Address)
@@ -338,41 +339,48 @@
 			vlog.Errorf("ipc: Listen on %v %v failed: %v", protocol, address, err)
 			return nil, err
 		}
+		ipep, ok := pep.(*inaming.Endpoint)
+		if !ok {
+			return nil, fmt.Errorf("failed translating internal endpoint data types")
+		}
 		// We have a goroutine for listening on proxy connections.
 		s.active.Add(1)
-		go func(ln stream.Listener, ep naming.Endpoint, proxy string) {
+		go func(ln stream.Listener, ep *inaming.Endpoint, proxy string) {
 			s.proxyListenLoop(ln, ep, proxy)
 			s.active.Done()
-		}(pln, pep, listenSpec.Proxy)
+		}(pln, ipep, listenSpec.Proxy)
 		s.listeners[pln] = nil
-		s.publisher.AddServer(s.publishEP(pep), s.servesMountTable)
+		// TODO(cnicolaou,p): AddServer no longer needs to take the
+		// servesMountTable bool since it can be extracted from the endpoint.
+		s.publisher.AddServer(s.publishEP(ipep, s.servesMountTable), s.servesMountTable)
 	} else {
-		s.publisher.AddServer(s.publishEP(ep), s.servesMountTable)
+		s.publisher.AddServer(s.publishEP(ep, s.servesMountTable), s.servesMountTable)
 	}
 	s.Unlock()
 	return ep, nil
 }
 
-func (s *server) publishEP(ep naming.Endpoint) string {
+func (s *server) publishEP(ep *inaming.Endpoint, servesMountTable bool) string {
 	var name string
 	if !s.servesMountTable {
 		// Make sure that client MountTable code doesn't try and
 		// ResolveStep past this final address.
 		name = "//"
 	}
+	ep.IsMountTable = servesMountTable
 	return naming.JoinAddressName(ep.String(), name)
 }
 
-func (s *server) proxyListenLoop(ln stream.Listener, ep naming.Endpoint, proxy string) {
+func (s *server) proxyListenLoop(ln stream.Listener, iep *inaming.Endpoint, proxy string) {
 	const (
 		min = 5 * time.Millisecond
 		max = 5 * time.Minute
 	)
 	for {
-		s.listenLoop(ln, ep)
+		s.listenLoop(ln, iep)
 		// The listener is done, so:
 		// (1) Unpublish its name
-		s.publisher.RemoveServer(s.publishEP(ep))
+		s.publisher.RemoveServer(s.publishEP(iep, s.servesMountTable))
 		// (2) Reconnect to the proxy unless the server has been stopped
 		backoff := min
 		ln = nil
@@ -384,9 +392,17 @@
 					vlog.VI(1).Infof("Failed to resolve proxy %q (%v), will retry in %v", proxy, err, backoff)
 					break
 				}
+				var ep naming.Endpoint
 				ln, ep, err = s.streamMgr.Listen(inaming.Network, resolved, s.listenerOpts...)
 				if err == nil {
-					vlog.VI(1).Infof("Reconnected to proxy at %q listener: (%v, %v)", proxy, ln, ep)
+					var ok bool
+					iep, ok = ep.(*inaming.Endpoint)
+					if !ok {
+						vlog.Errorf("failed translating internal endpoint data types")
+						ln = nil
+						continue
+					}
+					vlog.VI(1).Infof("Reconnected to proxy at %q listener: (%v, %v)", proxy, ln, iep)
 					break
 				}
 				if backoff = backoff * 2; backoff > max {
@@ -397,8 +413,13 @@
 				return
 			}
 		}
+		// TODO(cnicolaou,ashankar): this won't work when we are both
+		// proxying and publishing locally, which is the common case.
+		// listenLoop, dhcpLoop and the original publish are all publishing
+		// addresses to the same name, but the client is not smart enough
+		// to choose sensibly between them.
 		// (3) reconnected, publish new address
-		s.publisher.AddServer(s.publishEP(ep), s.servesMountTable)
+		s.publisher.AddServer(s.publishEP(iep, s.servesMountTable), s.servesMountTable)
 		s.Lock()
 		s.listeners[ln] = nil
 		s.Unlock()
@@ -438,7 +459,7 @@
 	for _, a := range addrs {
 		if ip := netstate.AsIP(a); ip != nil {
 			dhcpl.ep.Address = net.JoinHostPort(ip.String(), dhcpl.port)
-			fn(s.publishEP(dhcpl.ep))
+			fn(s.publishEP(dhcpl.ep, s.servesMountTable))
 		}
 	}
 }
@@ -459,6 +480,11 @@
 				s.Unlock()
 				return
 			}
+			// TODO(cnicolaou,ashankar): this won't work when we are both
+			// proxying and publishing locally, which is the common case.
+			// listenLoop, dhcpLoop and the original publish are all publishing
+			// addresses to the same name, but the client is not smart enough
+			// to choose sensibly between them.
 			publisher := s.publisher
 			s.Unlock()
 			switch setting.Name() {
diff --git a/runtimes/google/ipc/stream/benchmark/throughput_flow.go b/runtimes/google/ipc/stream/benchmark/throughput_flow.go
index 01d925b..ff69e6f 100644
--- a/runtimes/google/ipc/stream/benchmark/throughput_flow.go
+++ b/runtimes/google/ipc/stream/benchmark/throughput_flow.go
@@ -5,8 +5,6 @@
 	"testing"
 
 	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/manager"
-	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/sectest"
-	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"
 	"veyron.io/veyron/veyron2"
 	"veyron.io/veyron/veyron2/ipc/stream"
 	"veyron.io/veyron/veyron2/naming"
@@ -27,11 +25,9 @@
 // that calling stream.Manager.Dial to each of the endpoints will end up
 // creating a new VIF.
 func createListeners(mode veyron2.VCSecurityLevel, m stream.Manager, N int) (servers []listener, err error) {
-	// TODO(ashankar): Remove once PublicIDs are gone since at that point, if no Principal is provided, an anonymous one should be gereated within vc.go
-	serverP := vc.LocalPrincipal{sectest.NewPrincipal("server")}
 	for i := 0; i < N; i++ {
 		var l listener
-		if l.ln, l.ep, err = m.Listen("tcp", "127.0.0.1:0", mode, serverP); err != nil {
+		if l.ln, l.ep, err = m.Listen("tcp", "127.0.0.1:0", mode); err != nil {
 			return
 		}
 		servers = append(servers, l)
@@ -52,14 +48,12 @@
 	rchan := make(chan io.ReadCloser, nFlows)
 	wchan := make(chan io.WriteCloser, nFlows)
 
-	// TODO(ashankar): Remove once PublicIDs are gone since at that point, if no Principal is provided, an anonymous one should be gereated within vc.go
-	clientP := vc.LocalPrincipal{sectest.NewPrincipal("client")}
 	go func() {
 		defer close(wchan)
 		for i := 0; i < nVIFs; i++ {
 			ep := lns[i].ep
 			for j := 0; j < nVCsPerVIF; j++ {
-				vc, err := client.Dial(ep, mode, clientP)
+				vc, err := client.Dial(ep, mode)
 				if err != nil {
 					b.Error(err)
 					return
diff --git a/runtimes/google/ipc/stream/manager/manager_test.go b/runtimes/google/ipc/stream/manager/manager_test.go
index 5729c30..1130e2c 100644
--- a/runtimes/google/ipc/stream/manager/manager_test.go
+++ b/runtimes/google/ipc/stream/manager/manager_test.go
@@ -320,7 +320,7 @@
 
 	// Have the server read from each flow and write to rchan.
 	rchan := make(chan string)
-	ln, ep, err := server.Listen("tcp", "127.0.0.1:0", newPrincipal("server"))
+	ln, ep, err := server.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -356,7 +356,7 @@
 	var vcs [nVCs]stream.VC
 	for i := 0; i < nVCs; i++ {
 		var err error
-		vcs[i], err = client.Dial(ep, newPrincipal("client"))
+		vcs[i], err = client.Dial(ep)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -433,7 +433,6 @@
 
 func TestServerRestartDuringClientLifetime(t *testing.T) {
 	client := InternalNew(naming.FixedRoutingID(0xcccccccc))
-	clientP := newPrincipal("client") // TODO(ashankar): Remove. Once the PublicID code is gone anonymous principals should be generated within vc.go if one is not provided.
 	server := blackbox.HelperCommand(t, "runServer", "127.0.0.1:0")
 	server.Cmd.Start()
 	addr, err := server.ReadLineFromChild()
@@ -444,12 +443,12 @@
 	if err != nil {
 		t.Fatalf("inaming.NewEndpoint(%q): %v", addr, err)
 	}
-	if _, err := client.Dial(ep, clientP); err != nil {
+	if _, err := client.Dial(ep); err != nil {
 		t.Fatal(err)
 	}
 	server.Cleanup()
 	// A new VC cannot be created since the server is dead
-	if _, err := client.Dial(ep, clientP); err == nil {
+	if _, err := client.Dial(ep); err == nil {
 		t.Fatal("Expected client.Dial to fail since server is dead")
 	}
 	// Restarting the server, listening on the same address as before
@@ -459,7 +458,7 @@
 	if addr2, err := server.ReadLineFromChild(); addr2 != addr || err != nil {
 		t.Fatalf("Got (%q, %v) want (%q, nil)", addr2, err, addr)
 	}
-	if _, err := client.Dial(ep, clientP); err != nil {
+	if _, err := client.Dial(ep); err != nil {
 		t.Fatal(err)
 	}
 }
@@ -471,7 +470,7 @@
 
 func runServer(argv []string) {
 	server := InternalNew(naming.FixedRoutingID(0x55555555))
-	_, ep, err := server.Listen("tcp", argv[0], newPrincipal("server"))
+	_, ep, err := server.Listen("tcp", argv[0])
 	if err != nil {
 		fmt.Println(err)
 		return
diff --git a/runtimes/google/ipc/stream/proxy/proxy.go b/runtimes/google/ipc/stream/proxy/proxy.go
index 4099d71..683ea0c 100644
--- a/runtimes/google/ipc/stream/proxy/proxy.go
+++ b/runtimes/google/ipc/stream/proxy/proxy.go
@@ -127,14 +127,7 @@
 
 // New creates a new Proxy that listens for network connections on the provided
 // (network, address) pair and routes VC traffic between accepted connections.
-//
-// TODO(ashankar): Change principal to security.Principal once the old security model is ripped out.
-func New(rid naming.RoutingID, principal interface{}, network, address, pubAddress string) (*Proxy, error) {
-	if _, ok := principal.(security.Principal); principal != nil && !ok {
-		if _, ok := principal.(security.PrivateID); !ok {
-			return nil, fmt.Errorf("principal argument must be either a security.Principal or a security.PrivateID, not a %T", principal)
-		}
-	}
+func New(rid naming.RoutingID, principal security.Principal, network, address, pubAddress string) (*Proxy, error) {
 	ln, err := net.Listen(network, address)
 	if err != nil {
 		return nil, fmt.Errorf("net.Listen(%q, %q) failed: %v", network, address, err)
@@ -148,11 +141,7 @@
 		servers:    &servermap{m: make(map[naming.RoutingID]*server)},
 		processes:  make(map[*process]struct{}),
 		pubAddress: pubAddress,
-	}
-	if p, ok := principal.(security.Principal); ok {
-		proxy.principal = vc.LocalPrincipal{p}
-	} else if principal != nil {
-		proxy.principal = vc.FixedLocalID(principal.(security.PrivateID))
+		principal:  vc.LocalPrincipal{principal},
 	}
 	go proxy.listenLoop()
 	return proxy, nil
@@ -518,6 +507,11 @@
 		vc.Close("duplicate OpenVC request")
 		return nil
 	}
+	version, err := version.CommonVersion(m.DstEndpoint, m.SrcEndpoint)
+	if err != nil {
+		p.SendCloseVC(m.VCI, fmt.Errorf("incompatible IPC protocol versions: %v", err))
+		return nil
+	}
 	vc := vc.InternalNew(vc.Params{
 		VCI:          m.VCI,
 		LocalEP:      m.DstEndpoint,
@@ -525,6 +519,7 @@
 		Pool:         iobuf.NewPool(0),
 		ReserveBytes: message.HeaderSizeBytes,
 		Helper:       p,
+		Version:      version,
 	})
 	p.servers[m.VCI] = vc
 	proxyLog().Infof("Registered VC %v from server on process %v", vc, p)
diff --git a/runtimes/google/ipc/stream/proxy/proxy_test.go b/runtimes/google/ipc/stream/proxy/proxy_test.go
index 8803604..e705c6c 100644
--- a/runtimes/google/ipc/stream/proxy/proxy_test.go
+++ b/runtimes/google/ipc/stream/proxy/proxy_test.go
@@ -10,23 +10,14 @@
 
 	"veyron.io/veyron/veyron2/ipc/stream"
 	"veyron.io/veyron/veyron2/naming"
-	"veyron.io/veyron/veyron2/security"
 
 	_ "veyron.io/veyron/veyron/lib/testutil"
 	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/manager"
 	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/proxy"
+	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/sectest"
 	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"
-	isecurity "veyron.io/veyron/veyron/runtimes/google/security"
 )
 
-func newID(name string) security.PrivateID {
-	id, err := isecurity.NewPrivateID(name, nil)
-	if err != nil {
-		panic(err)
-	}
-	return id
-}
-
 func TestProxy(t *testing.T) {
 	proxy, err := proxy.New(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), nil, "tcp", "127.0.0.1:0", "")
 	if err != nil {
@@ -114,9 +105,9 @@
 	}
 }
 
-func TestProxyIdentity(t *testing.T) {
-	proxyID := newID("proxy")
-	proxy, err := proxy.New(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), proxyID, "tcp", "127.0.0.1:0", "")
+func TestProxyAuthentication(t *testing.T) {
+	pproxy := sectest.NewPrincipal("proxy")
+	proxy, err := proxy.New(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), pproxy, "tcp", "127.0.0.1:0", "")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -134,12 +125,12 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	if got, want := fmt.Sprintf("%v", flow.RemoteID()), fmt.Sprintf("%v", proxyID.PublicID()); got != want {
-		t.Errorf("Proxy has identity %q want %q", flow.RemoteID(), want)
+	if got, want := flow.RemoteBlessings(), pproxy.BlessingStore().Default(); !reflect.DeepEqual(got, want) {
+		t.Errorf("Proxy authenticated as [%v], want [%v]", got, want)
 	}
 }
 
-func TestServerIdentity(t *testing.T) {
+func TestServerBlessings(t *testing.T) {
 	proxy, err := proxy.New(naming.FixedRoutingID(0xbbbbbbbbbbbbbbbb), nil, "tcp", "127.0.0.1:0", "")
 	if err != nil {
 		t.Fatal(err)
@@ -147,11 +138,8 @@
 
 	server := manager.InternalNew(naming.FixedRoutingID(0x5555555555555555))
 	defer server.Shutdown()
-	serverID := newID("server")
-	if err != nil {
-		t.Fatal(err)
-	}
-	ln, ep, err := server.Listen(proxy.Endpoint().Network(), proxy.Endpoint().String(), vc.FixedLocalID(serverID))
+	pserver := sectest.NewPrincipal("server")
+	ln, ep, err := server.Listen(proxy.Endpoint().Network(), proxy.Endpoint().String(), vc.LocalPrincipal{pserver})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -174,8 +162,8 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	if got, want := flow.RemoteID(), serverID.PublicID(); !reflect.DeepEqual(got, want) {
-		t.Errorf("Got %q want %q", got, want)
+	if got, want := flow.RemoteBlessings(), pserver.BlessingStore().Default(); !reflect.DeepEqual(got, want) {
+		t.Errorf("Got [%v] want [%v]", got, want)
 	}
 }
 
diff --git a/runtimes/google/ipc/stream/vc/auth.go b/runtimes/google/ipc/stream/vc/auth.go
index e3b06ec..5746a99 100644
--- a/runtimes/google/ipc/stream/vc/auth.go
+++ b/runtimes/google/ipc/stream/vc/auth.go
@@ -75,6 +75,7 @@
 	errChannelIDMismatch         = errors.New("channel id does not match expectation")
 	errInvalidIdentityInMessage  = errors.New("invalid identity in authentication message")
 	errInvalidSignatureInMessage = errors.New("signature does not verify in authentication handshake message")
+	errNoCertificatesReceived    = errors.New("no certificates received")
 	errSingleCertificateRequired = errors.New("exactly one X.509 certificate chain with exactly one certificate is required")
 )
 
@@ -316,6 +317,9 @@
 	if err != nil {
 		return nil, err
 	}
+	if b == nil {
+		return nil, errNoCertificatesReceived
+	}
 	if !sig.Verify(b.PublicKey(), append(tag, crypter.ChannelBinding()...)) {
 		return nil, errInvalidSignatureInMessage
 	}
diff --git a/runtimes/google/ipc/stream/vc/init.go b/runtimes/google/ipc/stream/vc/init.go
index 8ff0aa5..96c21bd 100644
--- a/runtimes/google/ipc/stream/vc/init.go
+++ b/runtimes/google/ipc/stream/vc/init.go
@@ -1,6 +1,11 @@
 package vc
 
 import (
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rand"
+	"fmt"
+
 	isecurity "veyron.io/veyron/veyron/runtimes/google/security"
 
 	"veyron.io/veyron/veyron2/security"
@@ -8,10 +13,53 @@
 )
 
 var anonymousID security.PrivateID
+var anonymousPrincipal security.Principal
 
 func init() {
-	var err error
-	if anonymousID, err = isecurity.NewPrivateID("anonymous", nil); err != nil {
-		vlog.Fatalf("could not create anonymousID for IPCs: %s", err)
+	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		vlog.Fatalf("could not create private key for anonymous principal: %v", err)
 	}
+	store := &anonymousBlessingStore{k: security.NewECDSAPublicKey(&key.PublicKey)}
+	if anonymousPrincipal, err = security.CreatePrincipal(security.NewInMemoryECDSASigner(key), store, nil); err != nil {
+		vlog.Fatalf("could not create anonymous principal: %v", err)
+	}
+	if store.b, err = anonymousPrincipal.BlessSelf("anonymous"); err != nil {
+		vlog.Fatalf("failed to generate the one blessing to be used by the anonymous principal: %v", err)
+	}
+	if anonymousID, err = isecurity.NewPrivateID("anonymous", nil); err != nil {
+		vlog.Fatalf("could not create anonymousID for IPCs: %v", err)
+	}
+}
+
+// TODO(ashankar,ataly): Figure out what to do with this!
+// (Most likely move the BlessingStore implementation from veyron/runtimes/google/rt to veyron/security
+// and use that?)
+type anonymousBlessingStore struct {
+	k security.PublicKey
+	b security.Blessings
+}
+
+func (s *anonymousBlessingStore) Set(security.Blessings, security.BlessingPattern) (security.Blessings, error) {
+	return nil, fmt.Errorf("cannot store blessings with an anonymous principal")
+}
+
+func (s *anonymousBlessingStore) ForPeer(...string) security.Blessings {
+	return s.b
+}
+
+func (s *anonymousBlessingStore) SetDefault(security.Blessings) error {
+	return fmt.Errorf("cannot change default blessing associated with the anonymous principal")
+}
+
+func (s *anonymousBlessingStore) Default() security.Blessings {
+	return s.b
+}
+
+func (s *anonymousBlessingStore) PublicKey() security.PublicKey {
+	return s.k
+}
+
+func (anonymousBlessingStore) DebugString() string {
+	return "anonymous BlessingStore"
 }
diff --git a/runtimes/google/ipc/stream/vc/vc.go b/runtimes/google/ipc/stream/vc/vc.go
index f0b4ad9..0093009 100644
--- a/runtimes/google/ipc/stream/vc/vc.go
+++ b/runtimes/google/ipc/stream/vc/vc.go
@@ -397,11 +397,12 @@
 	}
 	switch securityLevel {
 	case veyron2.VCSecurityConfidential:
-		// TODO(ashankar): This should change to:
-		// if principal == nil {  either return error or principal = newAnonymousPrincipal }
-		if localID == nil && principal == nil {
+		if localID == nil {
 			localID = FixedLocalID(anonymousID)
 		}
+		if principal == nil {
+			principal = anonymousPrincipal
+		}
 	case veyron2.VCSecurityNone:
 		return nil
 	default:
@@ -437,7 +438,7 @@
 		rID, lID               security.PublicID
 		rBlessings, lBlessings security.Blessings
 	)
-	if principal == nil {
+	if vc.useOldSecurityModel() {
 		if rID, lID, err = authenticateAsClientOld(authConn, localID, crypter, vc.version); err != nil {
 			return vc.err(fmt.Errorf("authentication (using the deprecated PublicID objects) failed: %v", err))
 		}
@@ -451,14 +452,17 @@
 	vc.handshakeFID = handshakeFID
 	vc.authFID = authFID
 	vc.crypter = crypter
-	vc.localID = lID
-	vc.remoteID = rID
-	vc.localPrincipal = principal
-	vc.remoteBlessings = rBlessings
-	vc.localBlessings = lBlessings
+	if vc.useOldSecurityModel() {
+		vc.localID = lID
+		vc.remoteID = rID
+	} else {
+		vc.localPrincipal = principal
+		vc.remoteBlessings = rBlessings
+		vc.localBlessings = lBlessings
+	}
 	vc.mu.Unlock()
 
-	if principal != nil {
+	if !vc.useOldSecurityModel() {
 		vlog.VI(1).Infof("Client VC %v authenticated. RemoteBlessings:%v, LocalBlessings:%v", vc, rBlessings, lBlessings)
 	} else {
 		vlog.VI(1).Infof("Client VC %v authenticated using about-to-be-deleted protocol. RemoteID:%v LocalID:%v", vc, rID, lID)
@@ -511,6 +515,9 @@
 		if localID == nil {
 			localID = FixedLocalID(anonymousID)
 		}
+		if principal == nil {
+			principal = anonymousPrincipal
+		}
 	case veyron2.VCSecurityNone:
 		return finish(ln, nil)
 	default:
@@ -557,7 +564,7 @@
 			rID, lID               security.PublicID
 			rBlessings, lBlessings security.Blessings
 		)
-		if principal == nil {
+		if vc.useOldSecurityModel() {
 			if rID, lID, err = authenticateAsServerOld(authConn, localID, crypter, vc.version); err != nil {
 				sendErr(fmt.Errorf("Authentication failed (with soon-to-be-removed protocol): %v", err))
 				return
@@ -571,18 +578,21 @@
 
 		vc.mu.Lock()
 		vc.crypter = crypter
-		vc.localID = lID
-		vc.remoteID = rID
-		vc.localPrincipal = principal
-		vc.localBlessings = lBlessings
-		vc.remoteBlessings = rBlessings
+		if vc.useOldSecurityModel() {
+			vc.localID = lID
+			vc.remoteID = rID
+		} else {
+			vc.localPrincipal = principal
+			vc.localBlessings = lBlessings
+			vc.remoteBlessings = rBlessings
+		}
 		close(vc.acceptHandshakeDone)
 		vc.acceptHandshakeDone = nil
 		vc.mu.Unlock()
-		if principal == nil {
-			vlog.VI(1).Infof("Server VC %v authenticated using about-to-be-deleted protocol. RemoteID:%v LocalID:%v", vc, rID, lID)
-		} else {
+		if !vc.useOldSecurityModel() {
 			vlog.VI(1).Infof("Server VC %v authenticated. RemoteBlessings:%v, LocalBlessings:%v", vc, rBlessings, lBlessings)
+		} else {
+			vlog.VI(1).Infof("Server VC %v authenticated using about-to-be-deleted protocol. RemoteID:%v LocalID:%v", vc, rID, lID)
 		}
 		result <- HandshakeResult{ln, nil}
 	}()
@@ -671,7 +681,10 @@
 	vc.mu.Lock()
 	defer vc.mu.Unlock()
 	vc.waitForHandshakeLocked()
-	return anonymousIfNilPublicID(vc.localID)
+	if vc.useOldSecurityModel() {
+		return anonymousIfNilPublicID(vc.localID)
+	}
+	return nil
 }
 
 // RemoteID returns the identity of the remote end of the VC.
@@ -679,7 +692,10 @@
 	vc.mu.Lock()
 	defer vc.mu.Unlock()
 	vc.waitForHandshakeLocked()
-	return anonymousIfNilPublicID(vc.remoteID)
+	if vc.useOldSecurityModel() {
+		return anonymousIfNilPublicID(vc.remoteID)
+	}
+	return nil
 }
 
 // waitForHandshakeLocked blocks until an in-progress handshake (encryption
@@ -714,7 +730,9 @@
 		l = append(l, "Handshake not completed yet")
 	} else {
 		l = append(l, "Encryption: "+vc.crypter.String())
-		l = append(l, fmt.Sprintf("LocalPrincipal:%v LocalBlessings:%v RemoteBlessings:%v", vc.localPrincipal.PublicKey(), vc.localBlessings, vc.remoteBlessings))
+		if vc.localPrincipal != nil {
+			l = append(l, fmt.Sprintf("LocalPrincipal:%v LocalBlessings:%v RemoteBlessings:%v", vc.localPrincipal.PublicKey(), vc.localBlessings, vc.remoteBlessings))
+		}
 		l = append(l, fmt.Sprintf("LocalID:%q RemoteID:%q", anonymousIfNilPublicID(vc.localID), anonymousIfNilPublicID(vc.remoteID)))
 	}
 	for fid, f := range vc.flowMap {
@@ -725,6 +743,9 @@
 	return strings.Join(l, "\n")
 }
 
+// TODO(ashankar,ataly): Remove once the old security model is ripped out.
+func (vc *VC) useOldSecurityModel() bool { return vc.version < version.IPCVersion4 }
+
 // readHandlerImpl is an adapter for the readHandler interface required by
 // the reader type.
 type readHandlerImpl struct {
diff --git a/runtimes/google/ipc/stream/vc/vc_test.go b/runtimes/google/ipc/stream/vc/vc_test.go
index e380374..c469fe6 100644
--- a/runtimes/google/ipc/stream/vc/vc_test.go
+++ b/runtimes/google/ipc/stream/vc/vc_test.go
@@ -35,7 +35,7 @@
 	SecurityNone = veyron2.VCSecurityNone
 	SecurityTLS  = veyron2.VCSecurityConfidential
 
-	LatestVersion = version.IPCVersion3
+	LatestVersion = version.IPCVersion4
 )
 
 // testFlowEcho writes a random string of 'size' bytes on the flow and then
@@ -100,8 +100,6 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-	// TODO(ashankar): This should not be nil, but rather a dummy object (whose public
-	// key does not match that of the principal)
 	if flow.RemoteBlessings() != nil {
 		t.Errorf("Server sent blessing %v over insecure transport", flow.RemoteBlessings())
 	}
@@ -183,8 +181,8 @@
 func TestConnect(t *testing.T)    { testConnect(t, SecurityNone) }
 func TestConnectTLS(t *testing.T) { testConnect(t, SecurityTLS) }
 
-func testConnect_Version2(t *testing.T, security veyron2.VCSecurityLevel) {
-	h, vc := New(security, version.IPCVersion2, sectest.NewPrincipal("client"), sectest.NewPrincipal("server"))
+func testConnect_Version3(t *testing.T, security veyron2.VCSecurityLevel) {
+	h, vc := New(security, version.IPCVersion3, sectest.NewPrincipal("client"), sectest.NewPrincipal("server"))
 	defer h.Close()
 	flow, err := vc.Connect()
 	if err != nil {
@@ -192,8 +190,8 @@
 	}
 	testFlowEcho(t, flow, 10)
 }
-func TestConnect_Version2(t *testing.T)    { testConnect_Version2(t, SecurityNone) }
-func TestConnect_Version2TLS(t *testing.T) { testConnect_Version2(t, SecurityTLS) }
+func TestConnect_Version3(t *testing.T)    { testConnect_Version3(t, SecurityNone) }
+func TestConnect_Version3TLS(t *testing.T) { testConnect_Version3(t, SecurityTLS) }
 
 // helper function for testing concurrent operations on multiple flows over the
 // same VC.  Such tests are most useful when running the race detector.
@@ -448,6 +446,8 @@
 type endpoint naming.RoutingID
 
 func (e endpoint) Network() string             { return "test" }
+func (e endpoint) VersionedString(int) string  { return e.String() }
 func (e endpoint) String() string              { return naming.RoutingID(e).String() }
 func (e endpoint) RoutingID() naming.RoutingID { return naming.RoutingID(e) }
 func (e endpoint) Addr() net.Addr              { return nil }
+func (e endpoint) ServesMountTable() bool      { return false }
diff --git a/runtimes/google/ipc/stream/vif/vif.go b/runtimes/google/ipc/stream/vif/vif.go
index 06d27bd..c30a543 100644
--- a/runtimes/google/ipc/stream/vif/vif.go
+++ b/runtimes/google/ipc/stream/vif/vif.go
@@ -177,10 +177,22 @@
 	return vif, nil
 }
 
+func adjustIPCVersionForOldSecurityModel(in naming.Endpoint, opts []stream.VCOpt) naming.Endpoint {
+	out := in
+	for _, o := range opts {
+		if r, ok := o.(*version.Range); ok {
+			out = r.Endpoint(out.Addr().Network(), out.Addr().String(), out.RoutingID())
+			vlog.Infof("Adjusted Dialer endpoint from %v to %v for OpenVC message because the old security model is being used", in, out)
+		}
+	}
+	return out
+}
+
 // Dial creates a new VC to the provided remote identity, authenticating the VC
 // with the provided local identity.
 func (vif *VIF) Dial(remoteEP naming.Endpoint, opts ...stream.VCOpt) (stream.VC, error) {
-	vc, err := vif.newVC(vif.allocVCI(), vif.localEP, remoteEP, true)
+	localEP := adjustIPCVersionForOldSecurityModel(vif.localEP, opts)
+	vc, err := vif.newVC(vif.allocVCI(), localEP, remoteEP, true)
 	if err != nil {
 		return nil, err
 	}
@@ -189,7 +201,7 @@
 	err = vif.sendOnExpressQ(&message.OpenVC{
 		VCI:         vc.VCI(),
 		DstEndpoint: remoteEP,
-		SrcEndpoint: vif.localEP,
+		SrcEndpoint: localEP,
 		Counters:    counters})
 	if err != nil {
 		err = fmt.Errorf("vif.sendOnExpressQ(OpenVC) failed: %v", err)
@@ -667,11 +679,10 @@
 // ShutdownVCs closes all VCs established to the provided remote endpoint.
 // Returns the number of VCs that were closed.
 func (vif *VIF) ShutdownVCs(remote naming.Endpoint) int {
-	remoteStr := remote.String()
 	vcs := vif.vcMap.List()
 	n := 0
 	for _, vc := range vcs {
-		if vc.RemoteAddr().String() == remoteStr {
+		if naming.Compare(vc.RemoteAddr().RoutingID(), remote.RoutingID()) {
 			vlog.VI(1).Infof("VCI %d on VIF %s being closed because of ShutdownVCs call", vc.VCI(), vif)
 			vif.closeVCAndSendMsg(vc, "")
 			n++
diff --git a/runtimes/google/ipc/stream/vif/vif_test.go b/runtimes/google/ipc/stream/vif/vif_test.go
index afddf53..aec55c7 100644
--- a/runtimes/google/ipc/stream/vif/vif_test.go
+++ b/runtimes/google/ipc/stream/vif/vif_test.go
@@ -325,7 +325,7 @@
 	ep := tc.ep.Endpoint("test", "addr", naming.FixedRoutingID(0x5))
 	clientVC, _, err := createVC(client, server, ep)
 	if (err != nil) != tc.expectError {
-		t.Errorf("Error mismatch.  Wanted error: %v, got %v", tc.expectError, err)
+		t.Errorf("Error mismatch.  Wanted error: %v, got %v (client:%v, server:%v ep:%v)", tc.expectError, err, tc.client, tc.server, tc.ep)
 
 	}
 	if err != nil {
diff --git a/runtimes/google/ipc/version/version.go b/runtimes/google/ipc/version/version.go
index ca86911..33d251f 100644
--- a/runtimes/google/ipc/version/version.go
+++ b/runtimes/google/ipc/version/version.go
@@ -14,6 +14,10 @@
 	Min, Max version.IPCVersion
 }
 
+// TODO(ashankar): Remove when the transition to the new security API is complete.
+func (*Range) IPCClientOpt()   {}
+func (*Range) IPCStreamVCOpt() {}
+
 var (
 	// supportedRange represents the range of protocol verions supported by this
 	// implementation.
@@ -21,7 +25,7 @@
 	// change that's not both forward and backward compatible.
 	// Min should be incremented whenever we want to remove
 	// support for old protocol versions.
-	supportedRange = &Range{Min: version.IPCVersion2, Max: version.IPCVersion3}
+	supportedRange = &Range{Min: version.IPCVersion2, Max: version.IPCVersion4}
 
 	// Export the methods on supportedRange.
 	Endpoint           = supportedRange.Endpoint
diff --git a/runtimes/google/naming/endpoint.go b/runtimes/google/naming/endpoint.go
index a69ffbe..e2fefd9 100644
--- a/runtimes/google/naming/endpoint.go
+++ b/runtimes/google/naming/endpoint.go
@@ -29,10 +29,11 @@
 	RID           naming.RoutingID
 	MinIPCVersion version.IPCVersion
 	MaxIPCVersion version.IPCVersion
+	IsMountTable  bool
 }
 
 // NewEndpoint creates a new endpoint from a string as per naming.NewEndpoint
-func NewEndpoint(input string) (naming.Endpoint, error) {
+func NewEndpoint(input string) (*Endpoint, error) {
 	var ep Endpoint
 
 	// The prefix and suffix are optional.
@@ -54,6 +55,8 @@
 		err = ep.parseV1(parts)
 	case 2:
 		err = ep.parseV2(parts)
+	case 3:
+		err = ep.parseV3(parts)
 	default:
 		err = errInvalidEndpointString
 	}
@@ -112,6 +115,20 @@
 	return strconv.FormatUint(uint64(v), 10)
 }
 
+func parseMountTableFlag(input string) (bool, error) {
+	if len(input) == 1 {
+		switch f := input[0]; f {
+		case 'm':
+			return true, nil
+		case 's':
+			return false, nil
+		default:
+			return false, fmt.Errorf("%c is not one of 'm' or 's'", f)
+		}
+	}
+	return false, fmt.Errorf("flag is either missing or too long")
+}
+
 func (ep *Endpoint) parseV2(parts []string) error {
 	var err error
 	if len(parts) != 6 {
@@ -129,6 +146,20 @@
 	return nil
 }
 
+func (ep *Endpoint) parseV3(parts []string) error {
+	var err error
+	if len(parts) != 7 {
+		return errInvalidEndpointString
+	}
+	if err = ep.parseV2(parts[:6]); err != nil {
+		return err
+	}
+	if ep.IsMountTable, err = parseMountTableFlag(parts[6]); err != nil {
+		return fmt.Errorf("invalid mount table flag: %v", err)
+	}
+	return nil
+}
+
 func (ep *Endpoint) RoutingID() naming.RoutingID {
 	//nologcall
 	return ep.RID
@@ -137,19 +168,46 @@
 	//nologcall
 	return Network
 }
+
+var defaultVersion = 2
+
+func (ep *Endpoint) VersionedString(version int) string {
+	switch version {
+	default:
+		return ep.VersionedString(defaultVersion)
+	case 1:
+		return fmt.Sprintf("@1@%s@%s@@", ep.Protocol, ep.Address)
+	case 2:
+		return fmt.Sprintf("@2@%s@%s@%s@%s@%s@@",
+			ep.Protocol, ep.Address, ep.RID,
+			printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion))
+	case 3:
+		mt := "s"
+		if ep.IsMountTable {
+			mt = "m"
+		}
+		return fmt.Sprintf("@3@%s@%s@%s@%s@%s@%s@@",
+			ep.Protocol, ep.Address, ep.RID,
+			printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion),
+			mt)
+	}
+}
+
 func (ep *Endpoint) String() string {
 	//nologcall
-	return fmt.Sprintf("%s2@%s@%s@%s@%s@%s@@",
-		separator, ep.Protocol, ep.Address, ep.RID,
-		printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion))
+	return ep.VersionedString(defaultVersion)
 }
-func (ep *Endpoint) version() int { return 2 }
 
 func (ep *Endpoint) Addr() net.Addr {
 	//nologcall
 	return &addr{network: ep.Protocol, address: ep.Address}
 }
 
+func (ep *Endpoint) ServesMountTable() bool {
+	//nologcall
+	return true
+}
+
 type addr struct {
 	network, address string
 }
diff --git a/runtimes/google/naming/endpoint_test.go b/runtimes/google/naming/endpoint_test.go
index f0d036b..00135c5 100644
--- a/runtimes/google/naming/endpoint_test.go
+++ b/runtimes/google/naming/endpoint_test.go
@@ -29,6 +29,14 @@
 		MinIPCVersion: 2,
 		MaxIPCVersion: 3,
 	}
+	v3 := &Endpoint{
+		Protocol:      "tcp",
+		Address:       "batman.com:2345",
+		RID:           naming.FixedRoutingID(0x0),
+		MinIPCVersion: 2,
+		MaxIPCVersion: 3,
+		IsMountTable:  true,
+	}
 
 	testcasesA := []struct {
 		endpoint naming.Endpoint
@@ -53,10 +61,13 @@
 		String   string
 		Input    string
 		min, max version.IPCVersion
+		servesMT bool
 	}{
-		{v1, "@2@tcp@batman.com:1234@000000000000000000000000dabbad00@@@@", "", version.UnknownIPCVersion, version.UnknownIPCVersion},
-		{v2, "@2@tcp@batman.com:2345@000000000000000000000000dabbad00@1@10@@", "", 1, 10},
-		{v2hp, "@2@tcp@batman.com:2345@00000000000000000000000000000000@2@3@@", "batman.com:2345", 2, 3},
+		{v1, "@2@tcp@batman.com:1234@000000000000000000000000dabbad00@@@@", "", version.UnknownIPCVersion, version.UnknownIPCVersion, false},
+		{v2, "@2@tcp@batman.com:2345@000000000000000000000000dabbad00@1@10@@", "", 1, 10, false},
+		{v2hp, "@2@tcp@batman.com:2345@00000000000000000000000000000000@2@3@@", "batman.com:2345", 2, 3, false},
+		// the v3 format is ignored unless explicitly enabled.
+		{v3, "@2@tcp@batman.com:2345@00000000000000000000000000000000@2@3@@", "batman.com:2345", 2, 3, true},
 	}
 
 	for _, test := range testcasesB {
@@ -71,7 +82,8 @@
 			ep, err = NewEndpoint(str)
 		} else {
 			ep, err = NewEndpoint(naming.FormatEndpoint("tcp", str,
-				version.IPCVersionRange{test.min, test.max}))
+				version.IPCVersionRange{test.min, test.max},
+				naming.ServesMountTableOpt(test.servesMT)))
 		}
 		if err != nil {
 			t.Errorf("Endpoint(%q) failed with %v", str, err)
@@ -81,6 +93,25 @@
 			t.Errorf("Got endpoint %T = %#v, want %T = %#v for string %q", ep, ep, test.Endpoint, test.Endpoint, str)
 		}
 	}
+
+	// Enable V3 endpoints.
+	defaultVersion = 3
+	for _, c := range []struct {
+		servesMT bool
+		str      string
+	}{
+		{true, "@3@tcp@a:10@00000000000000000000000000000000@1@3@m@@"},
+		{false, "@3@tcp@a:10@00000000000000000000000000000000@1@3@s@@"},
+	} {
+		ep, _ := NewEndpoint(naming.FormatEndpoint("tcp", "a:10",
+			version.IPCVersionRange{1, 3},
+			naming.ServesMountTableOpt(c.servesMT)))
+		if got, want := ep.String(), c.str; got != want {
+			t.Errorf("got: %s, want: %s", got, want)
+		}
+	}
+	// Disable V3 endpoints.
+	defaultVersion = 2
 }
 
 type endpointTest struct {
diff --git a/runtimes/google/rt/ipc.go b/runtimes/google/rt/ipc.go
index 093ab53..0e1281a 100644
--- a/runtimes/google/rt/ipc.go
+++ b/runtimes/google/rt/ipc.go
@@ -7,14 +7,18 @@
 	iipc "veyron.io/veyron/veyron/runtimes/google/ipc"
 	imanager "veyron.io/veyron/veyron/runtimes/google/ipc/stream/manager"
 	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/vc"
+	iversion "veyron.io/veyron/veyron/runtimes/google/ipc/version"
 	ivtrace "veyron.io/veyron/veyron/runtimes/google/vtrace"
 
 	"veyron.io/veyron/veyron2"
 	"veyron.io/veyron/veyron2/context"
+	"veyron.io/veyron/veyron2/i18n"
 	"veyron.io/veyron/veyron2/ipc"
 	"veyron.io/veyron/veyron2/ipc/stream"
+	"veyron.io/veyron/veyron2/ipc/version"
 	"veyron.io/veyron/veyron2/naming"
 	"veyron.io/veyron/veyron2/security"
+	"veyron.io/veyron/veyron2/verror2"
 	"veyron.io/veyron/veyron2/vtrace"
 )
 
@@ -100,8 +104,10 @@
 		}
 	}
 	// Add the option that provides the local identity to the client.
-	otherOpts = append(otherOpts, rt.newLocalID(id))
-
+	otherOpts = append(otherOpts, rt.newLocalID(id), vc.LocalPrincipal{rt.principal})
+	if !rt.useNewSecurityModelInIPCClients {
+		otherOpts = append(otherOpts, &iversion.Range{Min: version.IPCVersion2, Max: version.IPCVersion3})
+	}
 	return iipc.InternalNewClient(sm, ns, otherOpts...)
 }
 
@@ -110,7 +116,10 @@
 }
 
 func (rt *vrt) NewContext() context.T {
-	ctx, _ := ivtrace.WithNewSpan(iipc.InternalNewContext(rt), "Root")
+	ctx := iipc.InternalNewContext(rt)
+	ctx = i18n.ContextWithLangID(ctx, rt.lang)
+	ctx = verror2.ContextWithComponentName(ctx, rt.program)
+	ctx, _ = ivtrace.WithNewSpan(ctx, "Root")
 	return ctx
 }
 
@@ -160,7 +169,7 @@
 		}
 	}
 	// Add the option that provides the local identity to the server.
-	otherOpts = append(otherOpts, rt.newLocalID(id))
+	otherOpts = append(otherOpts, rt.newLocalID(id), vc.LocalPrincipal{rt.principal})
 	ctx := rt.NewContext()
 
 	return iipc.InternalNewServer(ctx, sm, ns, otherOpts...)
diff --git a/runtimes/google/rt/ipc_test.go b/runtimes/google/rt/ipc_test.go
index 3f97b45..91492a5 100644
--- a/runtimes/google/rt/ipc_test.go
+++ b/runtimes/google/rt/ipc_test.go
@@ -1,11 +1,8 @@
 package rt_test
 
 import (
-	"fmt"
 	"reflect"
-	"sort"
 	"testing"
-	"time"
 
 	"veyron.io/veyron/veyron2"
 	"veyron.io/veyron/veyron2/ipc"
@@ -15,182 +12,149 @@
 
 	_ "veyron.io/veyron/veyron/lib/testutil"
 	"veyron.io/veyron/veyron/profiles"
-	isecurity "veyron.io/veyron/veyron/runtimes/google/security"
 	vsecurity "veyron.io/veyron/veyron/security"
 )
 
 type testService struct{}
 
-func (*testService) EchoIDs(call ipc.ServerCall) (server, client []string) {
-	return call.LocalID().Names(), call.RemoteID().Names()
+func (testService) EchoBlessings(call ipc.ServerCall) []string {
+	return call.RemoteBlessings().ForContext(call)
 }
 
-type S []string
-
-func newID(name string) security.PrivateID {
-	id, err := isecurity.NewPrivateID(name, nil)
+func newRT() veyron2.Runtime {
+	r, err := rt.New(veyron2.ForceNewSecurityModel{})
 	if err != nil {
 		panic(err)
 	}
-	return id
+	return r
 }
 
-func bless(blessor security.PrivateID, blessee security.PublicID, name string) security.PublicID {
-	blessedID, err := blessor.Bless(blessee, name, 5*time.Minute, nil)
+type rootPrincipal struct {
+	p security.Principal
+	b security.Blessings
+}
+
+func newRootPrincipal(name string) *rootPrincipal {
+	p, err := vsecurity.NewPrincipal()
 	if err != nil {
 		panic(err)
 	}
-	return blessedID
-}
-
-func add(store security.PublicIDStore, id security.PublicID, pattern security.BlessingPattern) {
-	if err := store.Add(id, pattern); err != nil {
+	b, err := p.BlessSelf(name)
+	if err != nil {
 		panic(err)
 	}
+	return &rootPrincipal{p, b}
 }
 
-func call(r veyron2.Runtime, client ipc.Client, name string) (clientNames, serverNames []string, err error) {
-	c, err := client.StartCall(r.NewContext(), name, "EchoIDs", nil)
+func (r *rootPrincipal) Bless(p security.Principal, extension string) security.Blessings {
+	b, err := r.p.Bless(p.PublicKey(), r.b, extension, security.UnconstrainedUse())
 	if err != nil {
-		return nil, nil, err
+		panic(err)
 	}
-	if err := c.Finish(&serverNames, &clientNames); err != nil {
-		return nil, nil, err
-	}
-	sort.Strings(clientNames)
-	sort.Strings(serverNames)
-	return
+	return b
 }
 
-func TestClientServerIDs(t *testing.T) {
-	stopServer := func(server ipc.Server) {
-		if err := server.Stop(); err != nil {
-			t.Fatalf("server.Stop failed: %s", err)
+func union(blessings ...security.Blessings) security.Blessings {
+	var ret security.Blessings
+	var err error
+	for _, b := range blessings {
+		if ret, err = security.UnionOfBlessings(ret, b); err != nil {
+			panic(err)
 		}
 	}
+	return ret
+}
+
+func TestClientServerBlessings(t *testing.T) {
 	var (
-		self   = newID("self")
-		google = newID("google")
-		veyron = newID("veyron")
+		rootAlpha, rootBeta, rootUnrecognized = newRootPrincipal("alpha"), newRootPrincipal("beta"), newRootPrincipal("unrecognized")
+		clientRT, serverRT                    = newRT(), newRT()
+		pclient, pserver                      = clientRT.Principal(), serverRT.Principal()
 
-		googleGmailService   = bless(google, self.PublicID(), "gmail")
-		googleYoutubeService = bless(google, self.PublicID(), "youtube")
-		veyronService        = bless(veyron, self.PublicID(), "service")
-		googleGmailClient    = bless(google, self.PublicID(), "gmailClient")
-		googleYoutubeClient  = bless(google, self.PublicID(), "youtubeClient")
-		veyronClient         = bless(veyron, self.PublicID(), "client")
+		// A bunch of blessings
+		alphaClient        = rootAlpha.Bless(pclient, "client")
+		betaClient         = rootBeta.Bless(pclient, "client")
+		unrecognizedClient = rootUnrecognized.Bless(pclient, "client")
+
+		alphaServer        = rootAlpha.Bless(pserver, "server")
+		betaServer         = rootBeta.Bless(pserver, "server")
+		unrecognizedServer = rootUnrecognized.Bless(pserver, "server")
 	)
-	isecurity.TrustIdentityProviders(google)
-	isecurity.TrustIdentityProviders(veyron)
+	// Setup the client's blessing store
+	pclient.BlessingStore().Set(alphaClient, "alpha/server")
+	pclient.BlessingStore().Set(betaClient, "beta/...")
+	pclient.BlessingStore().Set(unrecognizedClient, security.AllPrincipals)
 
-	serverR, err := rt.New(veyron2.RuntimeID(self))
+	tests := []struct {
+		server security.Blessings // Blessings presented by the server.
+
+		// Expected output
+		wantServer []string // Client's view of the server's blessings
+		wantClient []string // Server's view fo the client's blessings
+	}{
+		{
+			server:     unrecognizedServer,
+			wantServer: nil,
+			wantClient: nil,
+		},
+		{
+			server:     alphaServer,
+			wantServer: []string{"alpha/server"},
+			wantClient: []string{"alpha/client"},
+		},
+		{
+			server:     union(alphaServer, betaServer),
+			wantServer: []string{"alpha/server", "beta/server"},
+			wantClient: []string{"alpha/client", "beta/client"},
+		},
+	}
+
+	// Have the client and server both trust both the root principals.
+	for _, rt := range []veyron2.Runtime{clientRT, serverRT} {
+		for _, root := range []*rootPrincipal{rootAlpha, rootBeta} {
+			if err := rt.Principal().AddToRoots(root.b); err != nil {
+				t.Fatal(err)
+			}
+		}
+	}
+	// Start the server process.
+	server, err := serverRT.NewServer()
 	if err != nil {
-		t.Fatalf("rt.New() failed: %s", err)
+		t.Fatal(err)
 	}
-	clientR, err := rt.New(veyron2.RuntimeID(self))
-	if err != nil {
-		t.Fatalf("rt.New() failed: %s", err)
+	defer server.Stop()
+	var serverObjectName string
+	if endpoint, err := server.ListenX(profiles.LocalListenSpec); err != nil {
+		t.Fatal(err)
+	} else {
+		serverObjectName = naming.JoinAddressName(endpoint.String(), "")
 	}
-
-	// Add PublicIDs for running "google/gmail" and "google/youtube" services to
-	// serverR's PublicIDStore. Since these PublicIDs are meant to be by
-	// servers only they are tagged with "".
-	add(serverR.PublicIDStore(), googleGmailService, "")
-	add(serverR.PublicIDStore(), googleYoutubeService, "")
-	// Add PublicIDs for communicating the "google/gmail" and "google/youtube" services
-	// to the clientR's PublicIDStore.
-	add(clientR.PublicIDStore(), googleGmailClient, "google/...")
-	add(clientR.PublicIDStore(), googleYoutubeClient, "google/youtube")
-
-	type testcase struct {
-		server, client                   security.PublicID
-		defaultPattern                   security.BlessingPattern
-		wantServerNames, wantClientNames []string
+	if err := server.Serve("", ipc.LeafDispatcher(testService{}, vsecurity.NewACLAuthorizer(vsecurity.OpenACL()))); err != nil {
+		t.Fatal(err)
 	}
-	tests := []testcase{
-		{
-			defaultPattern:  security.AllPrincipals,
-			wantServerNames: S{"self", "google/gmail", "google/youtube"},
-			wantClientNames: S{"self", "google/gmailClient", "google/youtubeClient"},
-		},
-		{
-			defaultPattern:  "google/gmail",
-			wantServerNames: S{"google/gmail"},
-			wantClientNames: S{"self", "google/gmailClient"},
-		},
-		{
-			defaultPattern:  "google/youtube",
-			wantServerNames: S{"google/youtube"},
-			wantClientNames: S{"self", "google/gmailClient", "google/youtubeClient"},
-		},
-		{
-			server:          veyronService,
-			defaultPattern:  security.AllPrincipals,
-			wantServerNames: S{"veyron/service"},
-			wantClientNames: S{"self"},
-		},
-		{
-			client:          veyronClient,
-			defaultPattern:  security.AllPrincipals,
-			wantServerNames: S{"self", "google/gmail", "google/youtube"},
-			wantClientNames: S{"veyron/client"},
-		},
-		{
-			server:          veyronService,
-			client:          veyronClient,
-			defaultPattern:  security.AllPrincipals,
-			wantServerNames: S{"veyron/service"},
-			wantClientNames: S{"veyron/client"},
-		},
-	}
-	name := func(t testcase) string {
-		return fmt.Sprintf("TestCase{clientPublicIDStore: %v, serverPublicIDStore: %v, client option: %v, server option: %v}", clientR.PublicIDStore(), serverR.PublicIDStore(), t.client, t.server)
-	}
+	// Let it rip!
 	for _, test := range tests {
-		if err := serverR.PublicIDStore().SetDefaultBlessingPattern(test.defaultPattern); err != nil {
-			t.Errorf("serverR.PublicIDStore.SetDefaultBlessingPattern failed: %s", err)
-			continue
-		}
-		server, err := serverR.NewServer(veyron2.LocalID(test.server))
+		// Create a new client per test so as to not re-use established authenticated VCs.
+		// TODO(ashankar,suharshs): Once blessings are exchanged "per-RPC", one client for all cases will suffice.
+		client, err := clientRT.NewClient()
 		if err != nil {
-			t.Errorf("serverR.NewServer(...) failed: %s", err)
+			t.Errorf("clientRT.NewClient failed: %v", err)
 			continue
 		}
-		endpoint, err := server.ListenX(profiles.LocalListenSpec)
-		if err != nil {
-			t.Errorf("error listening to service: ", err)
+		if err := pserver.BlessingStore().SetDefault(test.server); err != nil {
+			t.Errorf("pserver.SetDefault(%v) failed: %v", test.server, err)
 			continue
 		}
-		defer stopServer(server)
-		if err := server.Serve("", ipc.LeafDispatcher(&testService{},
-			vsecurity.NewACLAuthorizer(security.ACL{In: map[security.BlessingPattern]security.LabelSet{
-				security.AllPrincipals: security.AllLabels,
-			}}))); err != nil {
-			t.Errorf("error serving service: ", err)
-			continue
+		var gotClient []string
+		if call, err := client.StartCall(clientRT.NewContext(), serverObjectName, "EchoBlessings", nil); err != nil {
+			t.Errorf("client.StartCall failed: %v", err)
+		} else if err = call.Finish(&gotClient); err != nil {
+			t.Errorf("call.Finish failed: %v", err)
+		} else if !reflect.DeepEqual(gotClient, test.wantClient) {
+			t.Errorf("%v: Got %v, want %v for client blessings", test.server, gotClient, test.wantServer)
+		} else if gotServer, _ := call.RemoteBlessings(); !reflect.DeepEqual(gotServer, test.wantServer) {
+			t.Errorf("%v: Got %v, want %v for server blessings", test.server, gotServer, test.wantClient)
 		}
-
-		client, err := clientR.NewClient(veyron2.LocalID(test.client))
-		if err != nil {
-			t.Errorf("clientR.NewClient(...) failed: %s", err)
-			continue
-		}
-		defer client.Close()
-
-		clientNames, serverNames, err := call(clientR, client, naming.JoinAddressName(fmt.Sprintf("%v", endpoint), ""))
-		if err != nil {
-			t.Errorf("IPC failed: %s", err)
-			continue
-		}
-		sort.Strings(test.wantClientNames)
-		sort.Strings(test.wantServerNames)
-		if !reflect.DeepEqual(clientNames, test.wantClientNames) {
-			t.Errorf("TestCase: %s, Got clientNames: %v, want: %v", name(test), clientNames, test.wantClientNames)
-			continue
-		}
-		if !reflect.DeepEqual(serverNames, test.wantServerNames) {
-			t.Errorf("TestCase: %s, Got serverNames: %v, want: %v", name(test), serverNames, test.wantServerNames)
-			continue
-		}
+		client.Close()
 	}
 }
diff --git a/runtimes/google/rt/mgmt_test.go b/runtimes/google/rt/mgmt_test.go
index df084f2..e15eaa2 100644
--- a/runtimes/google/rt/mgmt_test.go
+++ b/runtimes/google/rt/mgmt_test.go
@@ -263,12 +263,11 @@
 	// refer to the global rt.R() function), but we take care to make sure
 	// that the "google" runtime we are trying to test in this package is
 	// the one being used.
-	r, _ := rt.New(veyron2.RuntimeOpt{veyron2.GoogleRuntimeName})
+	r, _ := rt.New(veyron2.RuntimeOpt{veyron2.GoogleRuntimeName}, veyron2.ForceNewSecurityModel{})
 	c := blackbox.HelperCommand(t, "app")
-	id := r.Identity()
-	idFile := security.SaveIdentityToFile(security.NewBlessedIdentity(id, "test"))
+	childcreds := security.NewVeyronCredentials(r.Principal(), "app")
 	configServer, configServiceName, ch := createConfigServer(t, r)
-	c.Cmd.Env = append(c.Cmd.Env, fmt.Sprintf("VEYRON_IDENTITY=%v", idFile),
+	c.Cmd.Env = append(c.Cmd.Env, fmt.Sprintf("VEYRON_CREDENTIALS=%v", childcreds),
 		fmt.Sprintf("%v=%v", mgmt.ParentNodeManagerConfigKey, configServiceName))
 	c.Cmd.Start()
 	appCycleName := <-ch
@@ -279,7 +278,7 @@
 	return r, c, appCycle, func() {
 		configServer.Stop()
 		c.Cleanup()
-		os.Remove(idFile)
+		os.RemoveAll(childcreds)
 		// Don't do r.Cleanup() since the runtime needs to be used by
 		// more than one test case.
 	}
diff --git a/runtimes/google/rt/rt.go b/runtimes/google/rt/rt.go
index fa8ab10..3692c37 100644
--- a/runtimes/google/rt/rt.go
+++ b/runtimes/google/rt/rt.go
@@ -4,11 +4,13 @@
 	"flag"
 	"fmt"
 	"os"
+	"path/filepath"
 	"strings"
 	"sync"
 
 	"veyron.io/veyron/veyron2"
 	"veyron.io/veyron/veyron2/config"
+	"veyron.io/veyron/veyron2/i18n"
 	"veyron.io/veyron/veyron2/ipc"
 	"veyron.io/veyron/veyron2/ipc/stream"
 	"veyron.io/veyron/veyron2/naming"
@@ -39,13 +41,20 @@
 	debug      debugServer
 	nServers   int  // GUARDED_BY(mu)
 	cleaningUp bool // GUARDED_BY(mu)
+
+	// TODO(ashankar,ataly): Variables to help with the transition between the
+	// old and new security model. Will be removed once the transition is complete.
+	useNewSecurityModelInIPCClients bool
+
+	lang    i18n.LangID // Language, from environment variables.
+	program string      // Program name, from os.Args[0].
 }
 
 var _ veyron2.Runtime = (*vrt)(nil)
 
 // Implements veyron2/rt.New
 func New(opts ...veyron2.ROpt) (veyron2.Runtime, error) {
-	rt := &vrt{mgmt: new(mgmtImpl)}
+	rt := &vrt{mgmt: new(mgmtImpl), lang: i18n.LangIDFromEnv(), program: filepath.Base(os.Args[0])}
 	flag.Parse()
 	rt.initHTTPDebugServer()
 	nsRoots := []string{}
@@ -65,6 +74,8 @@
 			if v.Name != "google" && v.Name != "" {
 				return nil, fmt.Errorf("%q is the wrong name for this runtime", v.Name)
 			}
+		case veyron2.ForceNewSecurityModel:
+			rt.useNewSecurityModelInIPCClients = true
 		default:
 			return nil, fmt.Errorf("option has wrong type %T", o)
 		}
diff --git a/runtimes/google/rt/sectransition/sectransition.go b/runtimes/google/rt/sectransition/sectransition.go
new file mode 100644
index 0000000..1ac2734
--- /dev/null
+++ b/runtimes/google/rt/sectransition/sectransition.go
@@ -0,0 +1,72 @@
+// This package provides a shell test during the security model transition.
+package main
+
+import (
+	"flag"
+	"fmt"
+	"time"
+
+	"veyron.io/veyron/veyron/lib/signals"
+
+	"veyron.io/veyron/veyron2/ipc"
+	"veyron.io/veyron/veyron2/naming"
+	"veyron.io/veyron/veyron2/rt"
+	"veyron.io/veyron/veyron2/security"
+	"veyron.io/veyron/veyron2/vlog"
+)
+
+var runServer = flag.Bool("server", false, "If true, start a server. If false, start a client")
+
+type service struct{}
+
+func (service) Ping(call ipc.ServerCall) (string, error) {
+	return fmt.Sprintf("ClientBlessings: %v\nClientPublicID: %v", call.RemoteBlessings(), call.RemoteID()), nil
+}
+
+type authorizer struct{}
+
+func (authorizer) Authorize(security.Context) error { return nil }
+
+func main() {
+	r := rt.Init()
+	defer r.Cleanup()
+
+	if *runServer {
+		startServer(r.NewServer())
+	} else if len(flag.Args()) != 1 {
+		vlog.Fatalf("Expected exactly 1 argument, got %d (%v)", len(flag.Args()), flag.Args())
+	} else {
+		ctx, _ := r.NewContext().WithDeadline(time.Now().Add(10 * time.Second))
+		startClient(r.Client().StartCall(ctx, flag.Arg(0), "Ping", nil))
+	}
+}
+
+func startServer(server ipc.Server, err error) {
+	if err != nil {
+		vlog.Fatal(err)
+	}
+	defer server.Stop()
+
+	ep, err := server.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		vlog.Fatal(err)
+	}
+	fmt.Println("SERVER:", naming.JoinAddressName(ep.String(), ""))
+	server.Serve("", ipc.LeafDispatcher(service{}, authorizer{}))
+	<-signals.ShutdownOnSignals()
+}
+
+func startClient(call ipc.Call, err error) {
+	if err != nil {
+		vlog.Fatal(err)
+	}
+	var result string
+	var apperr error
+	if err = call.Finish(&result, &apperr); err != nil {
+		vlog.Fatalf("ipc.Call.Finish error: %v", err)
+	}
+	if apperr != nil {
+		vlog.Fatalf("Application error: %v", apperr)
+	}
+	fmt.Println(result)
+}
diff --git a/runtimes/google/rt/sectransition/test.sh b/runtimes/google/rt/sectransition/test.sh
new file mode 100755
index 0000000..d142e93
--- /dev/null
+++ b/runtimes/google/rt/sectransition/test.sh
@@ -0,0 +1,103 @@
+#!/bin/bash
+
+# Test compatibility of clients and servers using a combination of the old
+# and new security models (triggered by environment variables).
+
+. "${VEYRON_ROOT}/scripts/lib/shell_test.sh"
+
+readonly WORKDIR=$(shell::tmp_dir)
+set +e
+
+build() {
+  veyron go build veyron.io/veyron/veyron/runtimes/google/rt/sectransition || shell_test::fail "line ${LINENO}: failed to build sectransition binary"
+  veyron go build veyron.io/veyron/veyron/tools/identity || shell_test::fail "line ${LINENO}: failed to build identity"
+}
+
+
+startserver() {
+  # The server has access to both the old and new security model.
+  export VEYRON_IDENTITY="${WORKDIR}/old"
+  export VEYRON_CREDENTIALS="${WORKDIR}/new"
+  ./sectransition --server --logtostderr >"${SERVERLOG}" 2>&1 &
+  shell::wait_for "${SERVERLOG}" "SERVER"
+  local EP=$(grep "SERVER: " "${SERVERLOG}" | sed -e 's/SERVER: //')
+  echo "${EP}"
+}
+
+runclient() {
+  ./sectransition "${EP}" >"${CLIENTLOG}" 2>&1
+}
+
+oldmodel() {
+  awk '/ClientPublicID:/ {print $2}' "${CLIENTLOG}"
+}
+
+newmodel() {
+  awk '/ClientBlessings:/ {print $2}' "${CLIENTLOG}"
+}
+
+main() {
+  cd "${WORKDIR}"
+  build
+
+  # Generate an identity (old security model) that may be used by the client.
+  local -r OLD="${WORKDIR}/old"
+  ./identity generate "old" > "${OLD}"
+
+  local -r SERVERLOG="${WORKDIR}/server.log"
+  local -r CLIENTLOG="${WORKDIR}/client.log"
+  local -r EP=$(startserver)
+
+  # No environment variables set: PublicIDs from the old model should be exchanged.
+  unset VEYRON_IDENTITY
+  unset VEYRON_CREDENTIALS
+  runclient
+  echo "            No environment variables: PublicID:$(oldmodel), Blessings:$(newmodel)"
+  if [[ $(oldmodel) == "<nil>" ]]; then
+    shell_test::fail "line ${LINENO}: PublicID not set when neither environment variable is set"
+  fi
+  if [[ $(newmodel) != "<nil>" ]]; then
+    shell_test::fail "line ${LINENO}: Blessings should not be set when neither environment variable is set (was $(newmodel))"
+  fi
+
+
+  # Old model envvar is set: not the new one: PublicIDs from the old model should be exchanged.
+  export VEYRON_IDENTITY="${WORKDIR}/old"
+  unset VEYRON_CREDENTIALS
+  runclient
+  echo "                     VEYRON_IDENTITY: PublicID:$(oldmodel), Blessings:$(newmodel)"
+  if [[ $(oldmodel) == "<nil>" ]]; then
+    shell_test::fail "line ${LINENO}: PublicID not set when only VEYRON_IDENTITY is set"
+  fi
+  if [[ $(newmodel) != "<nil>" ]]; then
+    shell_test::fail "line ${LINENO}: Blessings should not be set when only VEYRON_IDENTITY is set (was $(newmodel))"
+  fi
+
+  # New model envvar is set:  Blessings should be exchanged.
+  unset VEYRON_IDENTITY
+  export VEYRON_CREDENTIALS="${WORKDIR}/new"
+  runclient
+  echo "                  VEYRON_CREDENTIALS: PublicID:$(oldmodel), Blessings:$(newmodel)"
+  if [[ $(oldmodel) != "<nil>" ]]; then
+    shell_test::fail "line ${LINENO}: PublicID should not be exchanged when VEYRON_CREDENTIALS is set (was $(oldmodel))"
+  fi
+  if [[ $(newmodel) == "<nil>" ]]; then
+    shell_test::fail "line ${LINENO}: Blessings should be exchanged when VEYRON_CREDENTIALS is set (was $(newmodel))"
+  fi
+
+  # Both environment variables are set: Blessings should be exchanged.
+  export VEYRON_IDENTITY="${WORKDIR}/old"
+  export VEYRON_CREDENTIALS="${WORKDIR}/new"
+  runclient
+  echo "VEYRON_IDENTITY & VEYRON_CREDENTIALS: PublicID:$(oldmodel), Blessings:$(newmodel)"
+  if [[ $(oldmodel) != "<nil>" ]]; then
+    shell_test::fail "line ${LINENO}: PublicID should not be exchanged when VEYRON_CREDENTIALS is set (was $(oldmodel))"
+  fi
+  if [[ $(newmodel) == "<nil>" ]]; then
+    shell_test::fail "line ${LINENO}: Blessings should be exchanged when VEYRON_CREDENTIALS is set (was $(newmodel))"
+  fi
+
+  shell_test::pass
+}
+
+main "$@"
diff --git a/runtimes/google/rt/security.go b/runtimes/google/rt/security.go
index 0370941..f034ce7 100644
--- a/runtimes/google/rt/security.go
+++ b/runtimes/google/rt/security.go
@@ -36,6 +36,9 @@
 }
 
 func (rt *vrt) initSecurity() error {
+	// Use the new security model in ipc.Client only if it was expicitly specified.
+	// At a later date, we will switch to using the new model always.
+	rt.useNewSecurityModelInIPCClients = rt.useNewSecurityModelInIPCClients || len(os.Getenv(VeyronCredentialsEnvVar)) > 0
 	if err := rt.initOldSecurity(); err != nil {
 		return err
 	}
diff --git a/runtimes/google/security/identity_test.go b/runtimes/google/security/identity_test.go
index d459e73..0802218 100644
--- a/runtimes/google/security/identity_test.go
+++ b/runtimes/google/security/identity_test.go
@@ -338,8 +338,6 @@
 		// Caveats
 		// Can only call "Play" at the Google service
 		cavOnlyPlay = mkCaveat(security.MethodCaveat("Play"))
-		// Can only talk to the "Google" service
-		cavOnlyGoogle = mkCaveat(security.PeerBlessingsCaveat("google"))
 	)
 
 	// We create a Caveat from the CaveatValidator "unregisteredCaveat".
@@ -383,6 +381,7 @@
 				{server: googleChain.PublicID(), method: "Hello", authErr: `security.methodCaveat=[Play] fails validation for method "Hello"`},
 			},
 		},
+		/* TODO(ashankar): Test case disabled since PeerBlessingsCaveat is disabled.
 		{
 			client: bless(cAlice, veyronChain, "alice", cavOnlyGoogle),
 			tests: []rpc{
@@ -391,6 +390,7 @@
 				{server: googleChain.PublicID(), method: "Play", authNames: S{"veyron/alice"}},
 			},
 		},
+		*/
 		{
 			client: bless(cAlice, veyronChain, "alice", cavUnregistered),
 			tests: []rpc{
@@ -400,6 +400,7 @@
 				{server: googleChain.PublicID(), method: "Hello", authErr: "caveat bytes could not be VOM-decoded"},
 			},
 		},
+		/* TODO(ashankar): Test case disabled since PeerBlessingsCaveat is disabled.
 		{
 			client: bless(cAlice, veyronChain, "alice", cavOnlyGoogle, cavOnlyPlay),
 			tests: []rpc{
@@ -409,13 +410,15 @@
 				{server: googleChain.PublicID(), method: "Play", authNames: S{"veyron/alice"}},
 			},
 		},
+		*/
 		{
-			client: bless(cAlice, veyronChain, "alice", cavOnlyGoogle, cavUnregistered),
+			client: bless(cAlice, veyronChain, "alice", cavUnregistered),
 			tests: []rpc{
 				{server: googleChain.PublicID(), method: "Play", authErr: "caveat bytes could not be VOM-decoded"},
 				{server: googleChain.PublicID(), method: "Hello", authErr: "caveat bytes could not be VOM-decoded"},
 			},
 		},
+		/* TODO(ashankar): Test case disabled since PeerBlessingsCaveat is disabled.
 		// client has multiple blessings
 		{
 			client: newSetPublicID(bless(cAlice, veyronChain, "valice", cavOnlyPlay, cavUnregistered), bless(cAlice, googleChain, "galice", cavOnlyGoogle)),
@@ -426,6 +429,7 @@
 				{server: googleChain.PublicID(), method: "Play", authNames: S{"google/galice"}},
 			},
 		},
+		*/
 	}
 	for _, d := range testdata {
 		// Validate that the client identity (with all its blessings) is valid for wire transmission.
@@ -496,6 +500,11 @@
 	}
 }
 
+/*
+TODO(ashankar): Test disabled because PeerBlessingCaveat has been disabled.
+In any case, we expect this whole package to be deleted (it is the "old" security
+model), so won't bother with trying to fix up the tests
+
 func TestAuthorizeWithThirdPartyCaveats(t *testing.T) {
 	mkveyron := func(id security.PrivateID, name string) security.PrivateID {
 		return derive(bless(id.PublicID(), veyronChain, name), id)
@@ -619,7 +628,7 @@
 		}
 	}
 }
-
+*/
 type SortedThirdPartyCaveats []security.ThirdPartyCaveat
 
 func (s SortedThirdPartyCaveats) Len() int { return len(s) }
diff --git a/security/acl_authorizer.go b/security/acl_authorizer.go
index 7a305ab..4ab195c 100644
--- a/security/acl_authorizer.go
+++ b/security/acl_authorizer.go
@@ -29,10 +29,8 @@
 	if ctx.LocalBlessings() != nil && ctx.RemoteBlessings() != nil && reflect.DeepEqual(ctx.LocalBlessings().PublicKey(), ctx.RemoteBlessings().PublicKey()) {
 		return nil
 	}
-	if newAPI := (ctx.LocalBlessings() != nil && ctx.RemoteBlessings() != nil); !newAPI {
-		if ctx.LocalID() != nil && ctx.RemoteID() != nil && reflect.DeepEqual(ctx.LocalID(), ctx.RemoteID()) {
-			return nil
-		}
+	if ctx.LocalID() != nil && ctx.RemoteID() != nil && reflect.DeepEqual(ctx.LocalID(), ctx.RemoteID()) {
+		return nil
 	}
 	var blessings []string
 	if ctx.RemoteBlessings() != nil {
diff --git a/security/blessingroots.go b/security/blessingroots.go
index 33bb145..5f314d8 100644
--- a/security/blessingroots.go
+++ b/security/blessingroots.go
@@ -1,8 +1,9 @@
 package security
 
 import (
-	"crypto/sha256"
+	"bytes"
 	"errors"
+	"fmt"
 	"sync"
 
 	"veyron.io/veyron/veyron/security/serialization"
@@ -28,8 +29,7 @@
 	if err != nil {
 		return "", err
 	}
-	rootBytesHash := sha256.Sum256(rootBytes)
-	return string(rootBytesHash[:]), nil
+	return string(rootBytes), nil
 }
 
 func (br *blessingRoots) Add(root security.PublicKey, pattern security.BlessingPattern) error {
@@ -71,6 +71,27 @@
 	return errors.New("PublicKey is not a recognized root for this blessing")
 }
 
+// DebugString return a human-readable string encoding of the roots
+// DebugString encodes all roots into a string in the following
+// format
+//
+// Public key   : Pattern
+// <public key> : <pattern>
+// ...
+// <public key> : <pattern>
+func (br *blessingRoots) DebugString() string {
+	const format = "%-47s : %s\n"
+	b := bytes.NewBufferString(fmt.Sprintf(format, "Public key", "Pattern"))
+	for keyBytes, pattern := range br.store {
+		key, err := security.UnmarshalPublicKey([]byte(keyBytes))
+		if err != nil {
+			return fmt.Sprintf("failed to decode public key: %v", err)
+		}
+		b.WriteString(fmt.Sprintf(format, key, pattern))
+	}
+	return b.String()
+}
+
 func (br *blessingRoots) save() error {
 	if (br.signer == nil) && (br.dir == "") {
 		return nil
diff --git a/security/blessingstore.go b/security/blessingstore.go
index 54b1b0b..b135580 100644
--- a/security/blessingstore.go
+++ b/security/blessingstore.go
@@ -1,6 +1,7 @@
 package security
 
 import (
+	"bytes"
 	"errors"
 	"fmt"
 	"reflect"
@@ -113,6 +114,25 @@
 	return fmt.Sprintf("{state: %v, publicKey: %v, dir: %v}", s.state, s.publicKey, s.dir)
 }
 
+// DebugString return a human-readable string encoding of the store
+// in the following format
+// Default blessing : <Default blessing of the store>
+//
+// Peer pattern : Blessings
+// <pattern>    : <blessings>
+// ...
+// <pattern>    : <blessings>
+func (br *blessingStore) DebugString() string {
+	const format = "%-30s : %s\n"
+	b := bytes.NewBufferString(fmt.Sprintf("Default blessings: %v\n", br.state.Default))
+
+	b.WriteString(fmt.Sprintf(format, "Peer pattern", "Blessings"))
+	for pattern, blessings := range br.state.Store {
+		b.WriteString(fmt.Sprintf(format, pattern, blessings))
+	}
+	return b.String()
+}
+
 func (s *blessingStore) save() error {
 	if (s.signer == nil) && (s.dir == "") {
 		return nil
diff --git a/services/identity/blesser/oauth.go b/services/identity/blesser/oauth.go
index 9463692..be6dd9f 100644
--- a/services/identity/blesser/oauth.go
+++ b/services/identity/blesser/oauth.go
@@ -64,17 +64,17 @@
 	})
 }
 
-func (b *googleOAuth) BlessUsingAccessToken(ctx ipc.ServerContext, accesstoken string) (vdlutil.Any, error) {
+func (b *googleOAuth) BlessUsingAccessToken(ctx ipc.ServerContext, accesstoken string) (vdlutil.Any, string, error) {
 	if len(b.accessTokenClients) == 0 {
-		return nil, fmt.Errorf("server not configured for blessing based on access tokens")
+		return nil, "", fmt.Errorf("server not configured for blessing based on access tokens")
 	}
 	// URL from: https://developers.google.com/accounts/docs/OAuth2UserAgent#validatetoken
 	tokeninfo, err := http.Get("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + accesstoken)
 	if err != nil {
-		return nil, fmt.Errorf("unable to use token: %v", err)
+		return nil, "", fmt.Errorf("unable to use token: %v", err)
 	}
 	if tokeninfo.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf("unable to verify access token: %v", tokeninfo.StatusCode)
+		return nil, "", fmt.Errorf("unable to verify access token: %v", tokeninfo.StatusCode)
 	}
 	// tokeninfo contains a JSON-encoded struct
 	var token struct {
@@ -88,7 +88,7 @@
 		AccessType    string `json:"access_type"`
 	}
 	if err := json.NewDecoder(tokeninfo.Body).Decode(&token); err != nil {
-		return "", fmt.Errorf("invalid JSON response from Google's tokeninfo API: %v", err)
+		return nil, "", fmt.Errorf("invalid JSON response from Google's tokeninfo API: %v", err)
 	}
 	audienceMatch := false
 	for _, c := range b.accessTokenClients {
@@ -99,31 +99,64 @@
 	}
 	if !audienceMatch {
 		vlog.Infof("Got access token [%+v], wanted one of client ids %v", token, b.accessTokenClients)
-		return "", fmt.Errorf("token not meant for this purpose, confused deputy? https://developers.google.com/accounts/docs/OAuth2UserAgent#validatetoken")
+		return nil, "", fmt.Errorf("token not meant for this purpose, confused deputy? https://developers.google.com/accounts/docs/OAuth2UserAgent#validatetoken")
 	}
 	if !token.VerifiedEmail {
-		return nil, fmt.Errorf("email not verified")
+		return nil, "", fmt.Errorf("email not verified")
+	}
+	if ctx.LocalPrincipal() == nil || ctx.RemoteBlessings() == nil {
+		// TODO(ataly, ashankar): Old security model, remove this block.
+		return b.blessOldModel(ctx, token.Email)
 	}
 	return b.bless(ctx, token.Email)
 }
 
-func (b *googleOAuth) bless(ctx ipc.ServerContext, name string) (vdlutil.Any, error) {
+func (b *googleOAuth) bless(ctx ipc.ServerContext, email string) (vdlutil.Any, string, error) {
+	var caveat security.Caveat
+	var err error
+	if b.revocationManager != nil {
+		// TODO(ataly, ashankar): Update the RevocationManager so that it uses the
+		// new security model.
+		revocationCaveat, err := b.revocationManager.NewCaveat(b.rt.Identity().PublicID(), b.dischargerLocation)
+		if err != nil {
+			return nil, "", err
+		}
+		caveat, err = security.NewCaveat(revocationCaveat)
+	} else {
+		caveat, err = security.ExpiryCaveat(time.Now().Add(b.duration))
+	}
+	if err != nil {
+		return nil, "", err
+	}
+	blessing, err := ctx.LocalPrincipal().Bless(ctx.RemoteBlessings().PublicKey(), ctx.LocalBlessings(), email, caveat)
+	if err != nil {
+		return nil, "", err
+	}
+	return blessing, email, nil
+}
+
+// DEPRECATED
+// TODO(ataly, ashankar): Remove this method once we get rid of the old security model.
+func (b *googleOAuth) blessOldModel(ctx ipc.ServerContext, name string) (vdlutil.Any, string, error) {
 	if len(b.domain) > 0 && !strings.HasSuffix(name, "@"+b.domain) {
-		return nil, fmt.Errorf("blessings for name %q are not allowed due to domain restriction", name)
+		return nil, "", fmt.Errorf("blessings for name %q are not allowed due to domain restriction", name)
 	}
 	self := b.rt.Identity()
 	var err error
 	// Use the blessing that was used to authenticate with the client to bless it.
 	if self, err = self.Derive(ctx.LocalID()); err != nil {
-		return nil, err
+		return nil, "", err
 	}
 	var revocationCaveat security.ThirdPartyCaveat
 	if b.revocationManager != nil {
 		revocationCaveat, err = b.revocationManager.NewCaveat(b.rt.Identity().PublicID(), b.dischargerLocation)
 		if err != nil {
-			return nil, err
+			return nil, "", err
 		}
 	}
-
-	return revocation.Bless(self, ctx.RemoteID(), name, b.duration, nil, revocationCaveat)
+	blessing, err := revocation.Bless(self, ctx.RemoteID(), name, b.duration, nil, revocationCaveat)
+	if err != nil {
+		return nil, "", err
+	}
+	return blessing, name, nil
 }
diff --git a/services/identity/googleoauth/handler.go b/services/identity/googleoauth/handler.go
index b8b805b..f008dce 100644
--- a/services/identity/googleoauth/handler.go
+++ b/services/identity/googleoauth/handler.go
@@ -497,19 +497,6 @@
 		},
 		Placeholder: "Comma-separated method names.",
 	},
-	"PeerBlessingsCaveat": {
-		New: func(args ...string) (security.Caveat, error) {
-			if len(args) < 1 {
-				return security.Caveat{}, fmt.Errorf("must pass at least one blessing pattern")
-			}
-			var patterns []security.BlessingPattern
-			for _, arg := range args {
-				patterns = append(patterns, security.BlessingPattern(arg))
-			}
-			return security.PeerBlessingsCaveat(patterns[0], patterns[1:]...)
-		},
-		Placeholder: "Comma-separated blessing patterns.",
-	},
 }
 
 // exchangeAuthCodeForEmail exchanges the authorization code (which must
diff --git a/services/identity/identity.vdl b/services/identity/identity.vdl
index bec7d91..faad788 100644
--- a/services/identity/identity.vdl
+++ b/services/identity/identity.vdl
@@ -14,13 +14,10 @@
 // veyron virtual circuit).
 // Thus, if Mallory possesses the access token associated with Alice's account,
 // she may be able to obtain a blessing with Alice's name on it.
-//
-// TODO(ashankar): Update this to use the new security model:
-// (blessing security.WireBlessing, error)
 type OAuthBlesser interface {
   // BlessUsingAccessToken uses the provided access token to obtain the email
-  // address and returns a blessing.
-  BlessUsingAccessToken(token string) (blessing any, err error)
+  // address and returns a blessing along with the email address.
+  BlessUsingAccessToken(token string) (blessing any, email string, err error)
 }
 
 // MacaroonBlesser returns a blessing given the provided macaroon string.
diff --git a/services/identity/identity.vdl.go b/services/identity/identity.vdl.go
index a947249..2525ee7 100644
--- a/services/identity/identity.vdl.go
+++ b/services/identity/identity.vdl.go
@@ -31,16 +31,13 @@
 // veyron virtual circuit).
 // Thus, if Mallory possesses the access token associated with Alice's account,
 // she may be able to obtain a blessing with Alice's name on it.
-//
-// TODO(ashankar): Update this to use the new security model:
-// (blessing security.WireBlessing, error)
 // OAuthBlesser is the interface the client binds and uses.
 // OAuthBlesser_ExcludingUniversal is the interface without internal framework-added methods
 // to enable embedding without method collisions.  Not to be used directly by clients.
 type OAuthBlesser_ExcludingUniversal interface {
 	// BlessUsingAccessToken uses the provided access token to obtain the email
-	// address and returns a blessing.
-	BlessUsingAccessToken(ctx _gen_context.T, token string, opts ..._gen_ipc.CallOpt) (reply _gen_vdlutil.Any, err error)
+	// address and returns a blessing along with the email address.
+	BlessUsingAccessToken(ctx _gen_context.T, token string, opts ..._gen_ipc.CallOpt) (blessing _gen_vdlutil.Any, email string, err error)
 }
 type OAuthBlesser interface {
 	_gen_ipc.UniversalServiceMethods
@@ -51,8 +48,8 @@
 type OAuthBlesserService interface {
 
 	// BlessUsingAccessToken uses the provided access token to obtain the email
-	// address and returns a blessing.
-	BlessUsingAccessToken(context _gen_ipc.ServerContext, token string) (reply _gen_vdlutil.Any, err error)
+	// address and returns a blessing along with the email address.
+	BlessUsingAccessToken(context _gen_ipc.ServerContext, token string) (blessing _gen_vdlutil.Any, email string, err error)
 }
 
 // BindOAuthBlesser returns the client stub implementing the OAuthBlesser
@@ -102,12 +99,12 @@
 	return _gen_veyron2.RuntimeFromContext(ctx).Client()
 }
 
-func (__gen_c *clientStubOAuthBlesser) BlessUsingAccessToken(ctx _gen_context.T, token string, opts ..._gen_ipc.CallOpt) (reply _gen_vdlutil.Any, err error) {
+func (__gen_c *clientStubOAuthBlesser) BlessUsingAccessToken(ctx _gen_context.T, token string, opts ..._gen_ipc.CallOpt) (blessing _gen_vdlutil.Any, email string, err error) {
 	var call _gen_ipc.Call
 	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "BlessUsingAccessToken", []interface{}{token}, opts...); err != nil {
 		return
 	}
-	if ierr := call.Finish(&reply, &err); ierr != nil {
+	if ierr := call.Finish(&blessing, &email, &err); ierr != nil {
 		err = ierr
 	}
 	return
@@ -173,6 +170,7 @@
 		},
 		OutArgs: []_gen_ipc.MethodArgument{
 			{Name: "blessing", Type: 65},
+			{Name: "email", Type: 3},
 			{Name: "err", Type: 66},
 		},
 	}
@@ -201,8 +199,8 @@
 	return
 }
 
-func (__gen_s *ServerStubOAuthBlesser) BlessUsingAccessToken(call _gen_ipc.ServerCall, token string) (reply _gen_vdlutil.Any, err error) {
-	reply, err = __gen_s.service.BlessUsingAccessToken(call, token)
+func (__gen_s *ServerStubOAuthBlesser) BlessUsingAccessToken(call _gen_ipc.ServerCall, token string) (blessing _gen_vdlutil.Any, email string, err error) {
+	blessing, email, err = __gen_s.service.BlessUsingAccessToken(call, token)
 	return
 }
 
diff --git a/services/mgmt/node/impl/app_invoker.go b/services/mgmt/node/impl/app_invoker.go
index 35a8268..8e4cdb6 100644
--- a/services/mgmt/node/impl/app_invoker.go
+++ b/services/mgmt/node/impl/app_invoker.go
@@ -488,7 +488,7 @@
 		return errOperationFailed
 	}
 	// Wait for the child process to start.
-	timeout := 20 * time.Second
+	timeout := 10 * time.Second
 	if err := handle.WaitForReady(timeout); err != nil {
 		vlog.Errorf("WaitForReady(%v) failed: %v", timeout, err)
 		return errOperationFailed
diff --git a/services/mgmt/node/impl/dispatcher.go b/services/mgmt/node/impl/dispatcher.go
index b63ea47..ed930d9 100644
--- a/services/mgmt/node/impl/dispatcher.go
+++ b/services/mgmt/node/impl/dispatcher.go
@@ -228,31 +228,42 @@
 	// The implementation of the node manager is split up into several
 	// invokers, which are instantiated depending on the receiver name
 	// prefix.
-	var receiver interface{}
 	switch components[0] {
 	case nodeSuffix:
-		receiver = node.NewServerNode(&nodeInvoker{
+		receiver := node.NewServerNode(&nodeInvoker{
 			callback: d.internal.callback,
 			updating: d.internal.updating,
 			config:   d.config,
 			disp:     d,
 		})
+		return ipc.ReflectInvoker(receiver), d.auth, nil
 	case appsSuffix:
-		receiver = node.NewServerApplication(&appInvoker{
+		receiver := node.NewServerApplication(&appInvoker{
 			callback: d.internal.callback,
 			config:   d.config,
 			suffix:   components[1:],
 		})
+		// TODO(caprita,rjkroege): Once we implement per-object ACLs
+		// (i.e. each installation and instance), replace d.auth with
+		// per-object authorizer.
+		return ipc.ReflectInvoker(receiver), d.auth, nil
 	case configSuffix:
 		if len(components) != 2 {
 			return nil, nil, errInvalidSuffix
 		}
-		receiver = inode.NewServerConfig(&configInvoker{
+		receiver := inode.NewServerConfig(&configInvoker{
 			callback: d.internal.callback,
 			suffix:   components[1],
 		})
+		// The nil authorizer ensures that only principals blessed by
+		// the node manager can talk back to it.  All apps started by
+		// the node manager should fall in that category.
+		//
+		// TODO(caprita,rjkroege): We should further refine this, by
+		// only allowing the app to update state referring to itself
+		// (and not other apps).
+		return ipc.ReflectInvoker(receiver), nil, nil
 	default:
 		return nil, nil, errInvalidSuffix
 	}
-	return ipc.ReflectInvoker(receiver), d.auth, nil
 }
diff --git a/services/mgmt/node/impl/impl_test.go b/services/mgmt/node/impl/impl_test.go
index 6d66f0f..32458f4 100644
--- a/services/mgmt/node/impl/impl_test.go
+++ b/services/mgmt/node/impl/impl_test.go
@@ -1,10 +1,10 @@
 package impl_test
 
 import (
-	//	"bytes"
+	"bytes"
 	"crypto/md5"
 	"encoding/base64"
-	//	"encoding/hex"
+	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
@@ -19,13 +19,12 @@
 	"strings"
 	"syscall"
 	"testing"
-	"time"
 
 	"veyron.io/veyron/veyron/lib/exec"
 	"veyron.io/veyron/veyron/lib/signals"
 	"veyron.io/veyron/veyron/lib/testutil/blackbox"
-	// tsecurity "veyron.io/veyron/veyron/lib/testutil/security"
-	// vsecurity "veyron.io/veyron/veyron/security"
+	tsecurity "veyron.io/veyron/veyron/lib/testutil/security"
+	vsecurity "veyron.io/veyron/veyron/security"
 	"veyron.io/veyron/veyron/services/mgmt/node/config"
 	"veyron.io/veyron/veyron/services/mgmt/node/impl"
 	suidhelper "veyron.io/veyron/veyron/services/mgmt/suidhelper/impl"
@@ -65,7 +64,7 @@
 	}
 
 	// All the tests require a runtime; so just create it here.
-	rt.Init()
+	rt.Init(veyron2.ForceNewSecurityModel{})
 
 	// Disable the cache because we will be manipulating/using the namespace
 	// across multiple processes and want predictable behaviour without
@@ -722,32 +721,26 @@
 
 type granter struct {
 	ipc.CallOpt
-	self     security.PrivateID
-	blessing security.PublicID
+	p         security.Principal
+	extension string
 }
 
-func (g *granter) Grant(id security.PublicID) (security.PublicID, error) {
-	var err error
-	g.blessing, err = g.self.Bless(id, "claimernode", 10*time.Minute, nil)
-	return g.blessing, err
+func (g *granter) Grant(other security.Blessings) (security.Blessings, error) {
+	return g.p.Bless(other.PublicKey(), g.p.BlessingStore().Default(), g.extension, security.UnconstrainedUse())
 }
 
-func newRuntimeClient(t *testing.T, id security.PrivateID) (veyron2.Runtime, ipc.Client) {
-	runtime, err := rt.New(veyron2.RuntimeID(id))
+func newRuntime(t *testing.T) veyron2.Runtime {
+	runtime, err := rt.New(veyron2.ForceNewSecurityModel{})
 	if err != nil {
 		t.Fatalf("rt.New() failed: %v", err)
 	}
 	runtime.Namespace().SetRoots(rt.R().Namespace().Roots()[0])
-	nodeClient, err := runtime.NewClient()
-	if err != nil {
-		t.Fatalf("rt.NewClient() failed %v", err)
-	}
-	return runtime, nodeClient
+	return runtime
 }
 
-func tryInstall(rt veyron2.Runtime, c ipc.Client) error {
+func tryInstall(rt veyron2.Runtime) error {
 	appsName := "nm//apps"
-	stub, err := node.BindApplication(appsName, c)
+	stub, err := node.BindApplication(appsName, rt.Client())
 	if err != nil {
 		return fmt.Errorf("BindApplication(%v) failed: %v", appsName, err)
 	}
@@ -757,9 +750,6 @@
 	return nil
 }
 
-// TODO(ashankar): Temporarily disabled during security model transition.
-// Fix up and restore!
-/*
 // TestNodeManagerClaim claims a nodemanager and tests ACL permissions on its methods.
 func TestNodeManagerClaim(t *testing.T) {
 	// Set up mount table, application, and binary repositories.
@@ -782,8 +772,13 @@
 	readPID(t, nm)
 
 	// Create an envelope for an app.
-	app := blackbox.HelperCommand(t, "app", "")
-	defer setupChildCommand(app)()
+	app := blackbox.HelperCommand(t, "app", "trapp")
+	// Ensure the child has a blessing that (a) allows it talk back to the
+	// node manager config service and (b) allows the node manager to talk
+	// to the app.  We achieve this by making the app's blessing derived
+	// from the node manager's blessing post claiming (which will be
+	// "mydevice").
+	defer setupChildCommandWithBlessing(app, "mydevice/child")()
 	appTitle := "google naps"
 	*envelope = *envelopeFromCmd(appTitle, app.Cmd)
 
@@ -792,39 +787,45 @@
 		t.Fatalf("BindNode failed: %v", err)
 	}
 
-	// Create a new identity and runtime.
-	claimerIdentity := tsecurity.NewBlessedIdentity(rt.R().Identity(), "claimer")
-	newRT, nodeClient := newRuntimeClient(t, claimerIdentity)
-	defer newRT.Cleanup()
+	selfRT := rt.R()
+	otherRT := newRuntime(t)
+	defer otherRT.Cleanup()
 
-	// Nodemanager should have open ACLs before we claim it and so an Install
-	// should succeed.
-	if err = tryInstall(newRT, nodeClient); err != nil {
-		t.Fatalf("%v", err)
+	// Nodemanager should have open ACLs before we claim it and so an Install from otherRT should succeed.
+	if err = tryInstall(otherRT); err != nil {
+		t.Fatal(err)
 	}
-	// Claim the nodemanager with this identity.
-	if err = nodeStub.Claim(rt.R().NewContext(), &granter{self: claimerIdentity}); err != nil {
-		t.Fatalf("Claim failed: %v", err)
+	// Claim the nodemanager with selfRT as <defaultblessing>/mydevice
+	if err = nodeStub.Claim(selfRT.NewContext(), &granter{p: selfRT.Principal(), extension: "mydevice"}); err != nil {
+		t.Fatal(err)
 	}
-	if err = tryInstall(newRT, nodeClient); err != nil {
-		t.Fatalf("%v", err)
+	// Installation should succeed since rt.R() (a.k.a. selfRT) is now the
+	// "owner" of the nodemanager.
+	appID := installApp(t)
+
+	// otherRT should be unable to install though, since the ACLs have changed now.
+	if err = tryInstall(otherRT); err == nil {
+		t.Fatalf("Install should have failed from otherRT")
 	}
-	// Try to install with a new identity. This should fail.
-	randomIdentity := tsecurity.NewBlessedIdentity(rt.R().Identity(), "random")
-	newRT, nodeClient = newRuntimeClient(t, randomIdentity)
-	defer newRT.Cleanup()
-	if err = tryInstall(newRT, nodeClient); err == nil {
-		t.Fatalf("Install should have failed with random identity")
+
+	// Create a script wrapping the test target that implements suidhelper.
+	generateSuidHelperScript(t, root)
+
+	// Create the local server that the app uses to let us know it's ready.
+	// TODO(caprita): Factor this code snippet out, it's pretty common.
+	server, _ := newServer()
+	defer server.Stop()
+	pingCh := make(chan string, 1)
+	if err := server.Serve("pingserver", ipc.LeafDispatcher(pingServerDisp(pingCh), nil)); err != nil {
+		t.Fatalf("Serve(%q, <dispatcher>) failed: %v", "pingserver", err)
 	}
-	// Try to install with the original identity. This should still work as the original identity
-	// name is a prefix of the identity used by newRT.
-	nodeClient, err = rt.R().NewClient()
-	if err != nil {
-		t.Fatalf("rt.NewClient() failed %v", err)
-	}
-	if err = tryInstall(rt.R(), nodeClient); err != nil {
-		t.Fatalf("%v", err)
-	}
+
+	// Start an instance of the app.
+	instanceID := startApp(t, appID)
+	<-pingCh
+	resolve(t, "trapp", 1)
+	suspendApp(t, appID, instanceID)
+
 	// TODO(gauthamt): Test that ACLs persist across nodemanager restarts
 }
 
@@ -838,6 +839,24 @@
 	root, cleanup := setupRootDir(t)
 	defer cleanup()
 
+	var (
+		proot = newRootPrincipal("root")
+		// The two "processes"/runtimes which will act as IPC clients to the
+		// nodemanager process.
+		selfRT  = rt.R()
+		otherRT = newRuntime(t)
+	)
+	defer otherRT.Cleanup()
+	// By default, selfRT and otherRT will have blessings generated based on the
+	// username/machine name running this process. Since these blessings will appear
+	// in ACLs, give them recognizable names.
+	if err := setDefaultBlessings(selfRT.Principal(), proot, "self"); err != nil {
+		t.Fatal(err)
+	}
+	if err := setDefaultBlessings(otherRT.Principal(), proot, "other"); err != nil {
+		t.Fatal(err)
+	}
+
 	// Set up the node manager.  Since we won't do node manager updates,
 	// don't worry about its application envelope and current link.
 	nm := blackbox.HelperCommand(t, "nodeManager", "nm", root, "unused app repo name", "unused curr link")
@@ -858,7 +877,7 @@
 	if err != nil {
 		t.Fatalf("BindNode failed: %v", err)
 	}
-	acl, etag, err := nodeStub.GetACL(rt.R().NewContext())
+	acl, etag, err := nodeStub.GetACL(selfRT.NewContext())
 	if err != nil {
 		t.Fatalf("GetACL failed:%v", err)
 	}
@@ -866,59 +885,42 @@
 		t.Fatalf("getACL expected:default, got:%v(%v)", etag, acl)
 	}
 
-	// Create a new identity and claim the node manager
-	claimerIdentity := tsecurity.NewBlessedIdentity(rt.R().Identity(), "claimer")
-	grant := &granter{self: claimerIdentity}
-	if err = nodeStub.Claim(rt.R().NewContext(), grant); err != nil {
-		t.Fatalf("Claim failed: %v", err)
+	// Claim the nodemanager as "root/self/mydevice"
+	if err = nodeStub.Claim(selfRT.NewContext(), &granter{p: selfRT.Principal(), extension: "mydevice"}); err != nil {
+		t.Fatal(err)
 	}
-	expectedACL := security.ACL{In: make(map[security.BlessingPattern]security.LabelSet)}
-	for _, name := range grant.blessing.Names() {
-		expectedACL.In[security.BlessingPattern(name)] = security.AllLabels
-	}
+	expectedACL := security.ACL{In: map[security.BlessingPattern]security.LabelSet{"root/self/mydevice": security.AllLabels}}
 	var b bytes.Buffer
 	if err := vsecurity.SaveACL(&b, expectedACL); err != nil {
 		t.Fatalf("Failed to saveACL:%v", err)
 	}
 	md5hash := md5.Sum(b.Bytes())
 	expectedETAG := hex.EncodeToString(md5hash[:])
-	acl, etag, err = nodeStub.GetACL(rt.R().NewContext())
-	if err != nil {
-		t.Fatalf("GetACL failed")
+	if acl, etag, err = nodeStub.GetACL(selfRT.NewContext()); err != nil {
+		t.Fatal(err)
 	}
 	if etag != expectedETAG {
 		t.Fatalf("getACL expected:%v(%v), got:%v(%v)", expectedACL, expectedETAG, acl, etag)
 	}
-	// Try to install with a new identity. This should fail.
-	randomIdentity := tsecurity.NewBlessedIdentity(rt.R().Identity(), "random")
-	newRT, nodeClient := newRuntimeClient(t, randomIdentity)
-	defer newRT.Cleanup()
-	if err = tryInstall(newRT, nodeClient); err == nil {
+	// Install from otherRT should fail, since it does not match the ACL.
+	if err = tryInstall(otherRT); err == nil {
 		t.Fatalf("Install should have failed with random identity")
 	}
-	newACL := security.ACL{In: make(map[security.BlessingPattern]security.LabelSet)}
-	for _, name := range randomIdentity.PublicID().Names() {
-		newACL.In[security.BlessingPattern(name)] = security.AllLabels
-	}
-	// SetACL with invalid etag
-	if err = nodeStub.SetACL(rt.R().NewContext(), newACL, "invalid"); err == nil {
+	newACL := security.ACL{In: map[security.BlessingPattern]security.LabelSet{"root/other": security.AllLabels}}
+	if err = nodeStub.SetACL(selfRT.NewContext(), newACL, "invalid"); err == nil {
 		t.Fatalf("SetACL should have failed with invalid etag")
 	}
-	if err = nodeStub.SetACL(rt.R().NewContext(), newACL, etag); err != nil {
-		t.Fatalf("SetACL failed:%v", err)
+	if err = nodeStub.SetACL(selfRT.NewContext(), newACL, etag); err != nil {
+		t.Fatal(err)
 	}
-	if err = tryInstall(newRT, nodeClient); err != nil {
-		t.Fatalf("Install failed with new identity:%v", err)
+	// Install should now fail with selfRT, which no longer matches the ACLs but succeed with otherRT, which does.
+	if err = tryInstall(selfRT); err == nil {
+		t.Errorf("Install should have failed with selfRT since it should no longer match the ACL")
 	}
-	// Try to install with the claimer identity. This should fail as the ACLs
-	// belong to the random identity
-	newRT, nodeClient = newRuntimeClient(t, claimerIdentity)
-	defer newRT.Cleanup()
-	if err = tryInstall(newRT, nodeClient); err == nil {
-		t.Fatalf("Install should have failed with claimer identity")
+	if err = tryInstall(otherRT); err != nil {
+		t.Error(err)
 	}
 }
-*/
 
 func TestNodeManagerGlob(t *testing.T) {
 	// Set up mount table, application, and binary repositories.
@@ -1007,3 +1009,34 @@
 		}
 	}
 }
+
+// rootPrincipal encapsulates a principal that acts as an "identity provider".
+type rootPrincipal struct {
+	p security.Principal
+	b security.Blessings
+}
+
+func (r *rootPrincipal) Bless(key security.PublicKey, as string) (security.Blessings, error) {
+	return r.p.Bless(key, r.b, as, security.UnconstrainedUse())
+}
+
+func newRootPrincipal(name string) *rootPrincipal {
+	p, err := vsecurity.NewPrincipal()
+	if err != nil {
+		panic(err)
+	}
+	b, err := p.BlessSelf(name)
+	if err != nil {
+		panic(err)
+	}
+	return &rootPrincipal{p, b}
+}
+
+func setDefaultBlessings(p security.Principal, root *rootPrincipal, name string) error {
+	b, err := root.Bless(p.PublicKey(), name)
+	if err != nil {
+		return err
+	}
+	tsecurity.SetDefaultBlessings(p, b)
+	return nil
+}
diff --git a/services/mgmt/node/impl/util_test.go b/services/mgmt/node/impl/util_test.go
index ad9e22a..37d3cfb 100644
--- a/services/mgmt/node/impl/util_test.go
+++ b/services/mgmt/node/impl/util_test.go
@@ -61,16 +61,20 @@
 // TODO(caprita): Move this setup into the blackbox lib.
 
 // setupChildCommand configures the child to use the right mounttable root
-// and identity.  It returns a cleanup function.
+// and blessings.  It returns a cleanup function.
 func setupChildCommand(child *blackbox.Child) func() {
+	return setupChildCommandWithBlessing(child, "child")
+}
+
+func setupChildCommandWithBlessing(child *blackbox.Child, blessing string) func() {
 	cmd := child.Cmd
 	for i, root := range rt.R().Namespace().Roots() {
 		cmd.Env = exec.Setenv(cmd.Env, fmt.Sprintf("NAMESPACE_ROOT%d", i), root)
 	}
-	idFile := security.SaveIdentityToFile(security.NewBlessedIdentity(rt.R().Identity(), "test"))
-	cmd.Env = exec.Setenv(cmd.Env, "VEYRON_IDENTITY", idFile)
+	childcreds := security.NewVeyronCredentials(rt.R().Principal(), blessing)
+	cmd.Env = exec.Setenv(cmd.Env, "VEYRON_CREDENTIALS", childcreds)
 	return func() {
-		os.Remove(idFile)
+		os.RemoveAll(childcreds)
 	}
 }
 
diff --git a/services/mounttable/lib/mounttable_test.go b/services/mounttable/lib/mounttable_test.go
index c773312..a8a6286 100644
--- a/services/mounttable/lib/mounttable_test.go
+++ b/services/mounttable/lib/mounttable_test.go
@@ -2,6 +2,7 @@
 
 import (
 	"errors"
+	"fmt"
 	"reflect"
 	"runtime/debug"
 	"sort"
@@ -26,14 +27,12 @@
 // stupidNS is a version of naming.Namespace that we can control.  This exists so that we have some
 // firm ground to stand on vis a vis the stub interface.
 type stupidNS struct {
-	id ipc.ClientOpt
+	r veyron2.Runtime
 }
 
-var (
-	rootID  = veyron2.LocalID(security.FakePublicID("root"))
-	bobID   = veyron2.LocalID(security.FakePublicID("bob"))
-	aliceID = veyron2.LocalID(security.FakePublicID("alice"))
-)
+// Simulate different processes with different runtimes.
+// rootRT is the one running the mounttable service.
+var rootRT, aliceRT, bobRT veyron2.Runtime
 
 const ttlSecs = 60 * 60
 
@@ -42,11 +41,10 @@
 	t.Fatal(string(debug.Stack()))
 }
 
-// quuxClient returns an ipc.Client that uses the simple namespace for name
-// resolution.
-func quuxClient(id ipc.ClientOpt) ipc.Client {
-	ns := stupidNS{id}
-	c, err := rt.R().NewClient(id, veyron2.Namespace(ns))
+// quuxClient returns an ipc.Client that would be used by the provided runtime
+// and uses the simple namespace for name resolution.
+func quuxClient(r veyron2.Runtime) ipc.Client {
+	c, err := r.NewClient(veyron2.Namespace(stupidNS{r}))
 	if err != nil {
 		panic(err)
 	}
@@ -74,11 +72,11 @@
 	}
 
 	// Resolve via another
-	objectPtr, err := mounttable.BindMountTable("/"+address+"//"+suffix, quuxClient(ns.id))
+	objectPtr, err := mounttable.BindMountTable("/"+address+"//"+suffix, quuxClient(ns.r))
 	if err != nil {
 		return nil, err
 	}
-	ss, suffix, err := objectPtr.ResolveStep(rt.R().NewContext())
+	ss, suffix, err := objectPtr.ResolveStep(ns.r.NewContext())
 	if err != nil {
 		return nil, err
 	}
@@ -119,12 +117,12 @@
 	return []string{}
 }
 
-func doMount(t *testing.T, name, service string, shouldSucceed bool, id ipc.ClientOpt) {
-	mtpt, err := mounttable.BindMountTable(name, quuxClient(id))
+func doMount(t *testing.T, name, service string, shouldSucceed bool, as veyron2.Runtime) {
+	mtpt, err := mounttable.BindMountTable(name, quuxClient(as))
 	if err != nil {
 		boom(t, "Failed to BindMountTable: %s", err)
 	}
-	if err := mtpt.Mount(rt.R().NewContext(), service, uint32(ttlSecs), 0, veyron2.RetryTimeoutOpt(0)); err != nil {
+	if err := mtpt.Mount(as.NewContext(), service, uint32(ttlSecs), 0, veyron2.RetryTimeoutOpt(0)); err != nil {
 		if shouldSucceed {
 			boom(t, "Failed to Mount %s onto %s: %s", service, name, err)
 		}
@@ -133,12 +131,12 @@
 	}
 }
 
-func doUnmount(t *testing.T, name, service string, shouldSucceed bool, id ipc.ClientOpt) {
-	mtpt, err := mounttable.BindMountTable(name, quuxClient(id))
+func doUnmount(t *testing.T, name, service string, shouldSucceed bool, as veyron2.Runtime) {
+	mtpt, err := mounttable.BindMountTable(name, quuxClient(as))
 	if err != nil {
 		boom(t, "Failed to BindMountTable: %s", err)
 	}
-	if err := mtpt.Unmount(rt.R().NewContext(), service, veyron2.RetryTimeoutOpt(0)); err != nil {
+	if err := mtpt.Unmount(as.NewContext(), service, veyron2.RetryTimeoutOpt(0)); err != nil {
 		if shouldSucceed {
 			boom(t, "Failed to Unmount %s onto %s: %s", service, name, err)
 		}
@@ -147,22 +145,22 @@
 	}
 }
 
-func create(t *testing.T, name, contents string) {
-	objectPtr, err := BindCollection(name, quuxClient(rootID))
+func export(t *testing.T, name, contents string, as veyron2.Runtime) {
+	objectPtr, err := BindCollection(name, quuxClient(as))
 	if err != nil {
 		boom(t, "Failed to BindCollection: %s", err)
 	}
-	if err := objectPtr.Export(rt.R().NewContext(), contents, true); err != nil {
+	if err := objectPtr.Export(as.NewContext(), contents, true); err != nil {
 		boom(t, "Failed to Export %s to %s: %s", name, contents, err)
 	}
 }
 
-func checkContents(t *testing.T, name, expected string, shouldSucceed bool, id ipc.ClientOpt) {
-	objectPtr, err := BindCollection(name, quuxClient(id))
+func checkContents(t *testing.T, name, expected string, shouldSucceed bool, as veyron2.Runtime) {
+	objectPtr, err := BindCollection(name, quuxClient(as))
 	if err != nil {
 		boom(t, "Failed to BindCollection: %s", err)
 	}
-	contents, err := objectPtr.Lookup(rt.R().NewContext(), veyron2.RetryTimeoutOpt(0))
+	contents, err := objectPtr.Lookup(as.NewContext(), veyron2.RetryTimeoutOpt(0))
 	if err != nil {
 		if shouldSucceed {
 			boom(t, "Failed to Lookup %s: %s", name, err)
@@ -178,13 +176,7 @@
 }
 
 func newMT(t *testing.T, acl string) (ipc.Server, string) {
-	// It is necessary for the private key of runtime's identity and
-	// the public key of the LocalIDOpts passed to clients to correspond.
-	// Since the LocalIDOpts are FakePublicIDs, we initialize the runtime
-	// below with a FakePrivateID. (Note all FakePublicIDs and FakePrivateIDs
-	// always have corresponding public and private keys respectively.)
-	r := rt.Init(veyron2.RuntimeID(security.FakePrivateID("irrelevant")))
-	server, err := r.NewServer(veyron2.ServesMountTableOpt(true))
+	server, err := rootRT.NewServer(veyron2.ServesMountTableOpt(true))
 	if err != nil {
 		boom(t, "r.NewServer: %s", err)
 	}
@@ -207,8 +199,7 @@
 }
 
 func newCollection(t *testing.T, acl string) (ipc.Server, string) {
-	r := rt.Init()
-	server, err := r.NewServer()
+	server, err := rootRT.NewServer()
 	if err != nil {
 		boom(t, "r.NewServer: %s", err)
 	}
@@ -238,69 +229,69 @@
 
 	// Mount the collection server into the mount table.
 	vlog.Infof("Mount the collection server into the mount table.")
-	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/stuff"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/stuff"), collectionName, true, rootRT)
 
 	// Create a few objects and make sure we can read them.
 	vlog.Infof("Create a few objects.")
-	create(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain")
-	create(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/in/spain"), "in spain")
-	create(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain")
+	export(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", rootRT)
+	export(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/in/spain"), "in spain", rootRT)
+	export(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", rootRT)
 	vlog.Infof("Make sure we can read them.")
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/in/spain"), "in spain", true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable//stuff/falls"), "falls mainly on the plain", false, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/nonexistant"), "falls mainly on the plain", false, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", true, bobID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", false, aliceID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/in/spain"), "in spain", true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable//stuff/falls"), "falls mainly on the plain", false, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/nonexistant"), "falls mainly on the plain", false, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", true, bobRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", false, aliceRT)
 
 	// Test multiple mounts.
 	vlog.Infof("Multiple mounts.")
-	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, true, rootID)
-	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/x/y"), collectionName, true, rootID)
-	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/alpha//beta"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, true, rootRT)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/x/y"), collectionName, true, rootRT)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/alpha//beta"), collectionName, true, rootRT)
 	vlog.Infof("Make sure we can read them.")
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/x/y/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/alpha/beta/falls"), "falls mainly on the plain", true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", true, aliceID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, bobID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/x/y/falls"), "falls mainly on the plain", true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/alpha/beta/falls"), "falls mainly on the plain", true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", true, aliceRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, bobRT)
 
 	// Test generic unmount.
 	vlog.Info("Test generic unmount.")
-	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), "", true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootID)
+	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), "", true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootRT)
 
 	// Test specific unmount.
 	vlog.Info("Test specific unmount.")
-	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), collectionName, true, rootID)
-	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), collectionName, true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), collectionName, true, rootRT)
+	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), collectionName, true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootRT)
 
 	// Try timing out a mount.
 	vlog.Info("Try timing out a mount.")
 	ft := NewFakeTimeClock()
 	setServerListClock(ft)
-	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/stuffWithTTL"), collectionName, true, rootID)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuffWithTTL/the/rain"), "the rain", true, rootID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/stuffWithTTL"), collectionName, true, rootRT)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuffWithTTL/the/rain"), "the rain", true, rootRT)
 	ft.advance(time.Duration(ttlSecs+4) * time.Second)
-	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuffWithTTL/the/rain"), "the rain", false, rootID)
+	checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuffWithTTL/the/rain"), "the rain", false, rootRT)
 
 	// Test unauthorized mount.
 	vlog.Info("Test unauthorized mount.")
-	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, false, bobID)
-	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, false, aliceID)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, false, bobRT)
+	doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, false, aliceRT)
 
-	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/x/y"), collectionName, false, bobID)
+	doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/x/y"), collectionName, false, bobRT)
 }
 
-func doGlob(t *testing.T, name, pattern string, id ipc.ClientOpt) []string {
-	mtpt, err := mounttable.BindMountTable(name, quuxClient(id))
+func doGlob(t *testing.T, name, pattern string, as veyron2.Runtime) []string {
+	mtpt, err := mounttable.BindMountTable(name, quuxClient(as))
 	if err != nil {
 		boom(t, "Failed to BindMountTable: %s", err)
 	}
-	stream, err := mtpt.Glob(rt.R().NewContext(), pattern)
+	stream, err := mtpt.Glob(as.NewContext(), pattern)
 	if err != nil {
 		boom(t, "Failed call to %s.Glob(%s): %s", name, pattern, err)
 	}
@@ -336,9 +327,9 @@
 
 	// set up a mount space
 	fakeServer := naming.JoinAddressName(estr, "//quux")
-	doMount(t, naming.JoinAddressName(estr, "//one/bright/day"), fakeServer, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//in/the/middle"), fakeServer, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//of/the/night"), fakeServer, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//one/bright/day"), fakeServer, true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//in/the/middle"), fakeServer, true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//of/the/night"), fakeServer, true, rootRT)
 
 	// Try various globs.
 	tests := []struct {
@@ -356,7 +347,7 @@
 		{"", []string{""}},
 	}
 	for _, test := range tests {
-		out := doGlob(t, naming.JoinAddressName(estr, "//"), test.in, rootID)
+		out := doGlob(t, naming.JoinAddressName(estr, "//"), test.in, rootRT)
 		checkMatch(t, test.expected, out)
 	}
 
@@ -365,11 +356,11 @@
 	{
 		name := naming.JoinAddressName(estr, "//of/the/night/two/dead/boys/got/up/to/fight")
 		pattern := "*"
-		m, err := mounttable.BindGlobbable(name, quuxClient(rootID))
+		m, err := mounttable.BindGlobbable(name, quuxClient(rootRT))
 		if err != nil {
 			boom(t, "Failed to BindMountTable: %s", err)
 		}
-		stream, err := m.Glob(rt.R().NewContext(), pattern)
+		stream, err := m.Glob(rootRT.NewContext(), pattern)
 		if err != nil {
 			boom(t, "Failed call to %s.Glob(%s): %s", name, pattern, err)
 		}
@@ -400,24 +391,24 @@
 
 	// set up a mount space
 	fakeServer := naming.JoinAddressName(estr, "quux")
-	doMount(t, naming.JoinAddressName(estr, "//one/bright/day"), fakeServer, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//a/b/c"), fakeServer, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//one/bright/day"), fakeServer, true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//a/b/c"), fakeServer, true, rootRT)
 
 	// Try various globs.
 	tests := []struct {
-		id       ipc.ClientOpt
+		as       veyron2.Runtime
 		in       string
 		expected []string
 	}{
-		{rootID, "*", []string{"one", "a"}},
-		{aliceID, "*", []string{"one", "a"}},
-		{bobID, "*", []string{"one"}},
-		{rootID, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c"}},
-		{aliceID, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c"}},
-		{bobID, "*/...", []string{"one", "one/bright", "one/bright/day"}},
+		{rootRT, "*", []string{"one", "a"}},
+		{aliceRT, "*", []string{"one", "a"}},
+		{bobRT, "*", []string{"one"}},
+		{rootRT, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c"}},
+		{aliceRT, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c"}},
+		{bobRT, "*/...", []string{"one", "one/bright", "one/bright/day"}},
 	}
 	for _, test := range tests {
-		out := doGlob(t, naming.JoinAddressName(estr, "//"), test.in, test.id)
+		out := doGlob(t, naming.JoinAddressName(estr, "//"), test.in, test.as)
 		checkMatch(t, test.expected, out)
 	}
 }
@@ -426,12 +417,12 @@
 	server, estr := newMT(t, "")
 	defer server.Stop()
 
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/endpoint"), naming.JoinAddressName(estr, "life/on/the/mississippi"), true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/hostport"), "/atrampabroad:8000", true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/hostport-endpoint-platypus"), "/@atrampabroad:8000@@", true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/not/rooted"), "atrampabroad:8000", false, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/no/port"), "/atrampabroad", false, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/endpoint"), "/@following the equator:8000@@@", false, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/endpoint"), naming.JoinAddressName(estr, "life/on/the/mississippi"), true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/hostport"), "/atrampabroad:8000", true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/hostport-endpoint-platypus"), "/@atrampabroad:8000@@", true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/not/rooted"), "atrampabroad:8000", false, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/no/port"), "/atrampabroad", false, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/endpoint"), "/@following the equator:8000@@@", false, rootRT)
 }
 
 func TestExpiry(t *testing.T) {
@@ -444,21 +435,21 @@
 
 	ft := NewFakeTimeClock()
 	setServerListClock(ft)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), collectionName, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b2"), collectionName, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b1"), collectionName, true, rootID)
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b2/c"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), collectionName, true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b2"), collectionName, true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b1"), collectionName, true, rootRT)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b2/c"), collectionName, true, rootRT)
 
-	checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootID))
+	checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootRT))
 	ft.advance(time.Duration(ttlSecs/2) * time.Second)
-	checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootID))
-	checkMatch(t, []string{"c"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable/a2/b2"), "*", rootID))
+	checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootRT))
+	checkMatch(t, []string{"c"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable/a2/b2"), "*", rootRT))
 	// Refresh only a1/b1.  All the other mounts will expire upon the next
 	// ft advance.
-	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), collectionName, true, rootID)
+	doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), collectionName, true, rootRT)
 	ft.advance(time.Duration(ttlSecs/2+4) * time.Second)
-	checkMatch(t, []string{"a1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*", rootID))
-	checkMatch(t, []string{"a1/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootID))
+	checkMatch(t, []string{"a1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*", rootRT))
+	checkMatch(t, []string{"a1/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootRT))
 }
 
 func TestBadACLs(t *testing.T) {
@@ -475,3 +466,42 @@
 		boom(t, "Expected error for missing '/' acl")
 	}
 }
+
+func init() {
+	// Create the runtime for each of the three "processes"
+	rootRT = rt.Init(veyron2.ForceNewSecurityModel{})
+	var err error
+	if aliceRT, err = rt.New(veyron2.ForceNewSecurityModel{}); err != nil {
+		panic(err)
+	}
+	if bobRT, err = rt.New(veyron2.ForceNewSecurityModel{}); err != nil {
+		panic(err)
+	}
+
+	// And setup their blessings so that they present "root", "alice" and "bob"
+	// and these blessings are recognized by the others.
+	principals := map[string]security.Principal{
+		"root":  rootRT.Principal(),
+		"alice": aliceRT.Principal(),
+		"bob":   bobRT.Principal(),
+	}
+	for name, p := range principals {
+		blessing, err := p.BlessSelf(name)
+		if err != nil {
+			panic(fmt.Sprintf("BlessSelf(%q) failed: %v", name, err))
+		}
+		// Share this blessing with all servers and use it when serving clients.
+		if err = p.BlessingStore().SetDefault(blessing); err != nil {
+			panic(fmt.Sprintf("%v: %v", blessing, err))
+		}
+		if _, err = p.BlessingStore().Set(blessing, security.AllPrincipals); err != nil {
+			panic(fmt.Sprintf("%v: %v", blessing, err))
+		}
+		// Have all principals trust the root of this blessing.
+		for _, other := range principals {
+			if err := other.AddToRoots(blessing); err != nil {
+				panic(err)
+			}
+		}
+	}
+}
diff --git a/services/mounttable/lib/neighborhood_test.go b/services/mounttable/lib/neighborhood_test.go
index edccc7f..cb95d4c 100644
--- a/services/mounttable/lib/neighborhood_test.go
+++ b/services/mounttable/lib/neighborhood_test.go
@@ -7,9 +7,7 @@
 	"testing"
 	"time"
 
-	"veyron.io/veyron/veyron2"
 	"veyron.io/veyron/veyron2/naming"
-	"veyron.io/veyron/veyron2/rt"
 	"veyron.io/veyron/veyron2/services/mounttable"
 	"veyron.io/veyron/veyron2/vlog"
 
@@ -26,10 +24,8 @@
 }
 
 func TestNeighborhood(t *testing.T) {
-	r := rt.Init()
-	id := veyron2.LocalID(rt.R().Identity().PublicID())
 	vlog.Infof("TestNeighborhood")
-	server, err := r.NewServer()
+	server, err := rootRT.NewServer()
 	if err != nil {
 		boom(t, "r.NewServer: %s", err)
 	}
@@ -63,7 +59,7 @@
 	// Wait for the mounttable to appear in mdns
 L:
 	for tries := 1; tries < 2; tries++ {
-		names := doGlob(t, naming.JoinAddressName(estr, "//"), "*", id)
+		names := doGlob(t, naming.JoinAddressName(estr, "//"), "*", rootRT)
 		t.Logf("names %v", names)
 		for _, n := range names {
 			if n == serverName {
@@ -74,18 +70,18 @@
 	}
 
 	// Make sure we get back a root for the server.
-	want, got := []string{""}, doGlob(t, naming.JoinAddressName(estr, "//"+serverName), "", id)
+	want, got := []string{""}, doGlob(t, naming.JoinAddressName(estr, "//"+serverName), "", rootRT)
 	if !reflect.DeepEqual(want, got) {
 		t.Errorf("Unexpected Glob result want: %q, got: %q", want, got)
 	}
 
 	// Make sure we can resolve through the neighborhood.
 	expectedSuffix := "a/b"
-	objectPtr, err := mounttable.BindMountTable(naming.JoinAddressName(estr, "//"+serverName+"/"+expectedSuffix), quuxClient(id))
+	objectPtr, err := mounttable.BindMountTable(naming.JoinAddressName(estr, "//"+serverName+"/"+expectedSuffix), quuxClient(rootRT))
 	if err != nil {
 		boom(t, "BindMountTable: %s", err)
 	}
-	servers, suffix, err := objectPtr.ResolveStep(r.NewContext())
+	servers, suffix, err := objectPtr.ResolveStep(rootRT.NewContext())
 	if err != nil {
 		boom(t, "resolveStep: %s", err)
 	}
diff --git a/services/mounttable/lib/testdata/test.acl b/services/mounttable/lib/testdata/test.acl
index 9ffe006..597dda9 100644
--- a/services/mounttable/lib/testdata/test.acl
+++ b/services/mounttable/lib/testdata/test.acl
@@ -1,5 +1,5 @@
 {
-"/": {"In": {"fake/root": "RW", "...": "R"}},
-"/stuff": {"In": {"fake/root": "RW", "fake/bob": "R"}},
-"/a": {"In": {"fake/root": "RW", "fake/alice": "R"}}
+"/": {"In": {"root": "RW", "...": "R"}},
+"/stuff": {"In": {"root": "RW", "bob": "R"}},
+"/a": {"In": {"root": "RW", "alice": "R"}}
 }
\ No newline at end of file
diff --git a/tools/naming/simulator/driver.go b/tools/naming/simulator/driver.go
index 60028b5..db4748e 100644
--- a/tools/naming/simulator/driver.go
+++ b/tools/naming/simulator/driver.go
@@ -108,8 +108,8 @@
 
 	shell := modules.NewShell()
 	defer shell.Cleanup(os.Stderr, os.Stderr)
-	if os.Getenv("VEYRON_IDENTITY") == "" {
-		shell.CreateAndUseNewID()
+	if os.Getenv("VEYRON_CREDENTIALS") == "" {
+		shell.CreateAndUseNewCredentials()
 	}
 
 	core.Install(shell)
diff --git a/tools/principal/bless.go b/tools/principal/bless.go
new file mode 100644
index 0000000..578cc03
--- /dev/null
+++ b/tools/principal/bless.go
@@ -0,0 +1,135 @@
+package main
+
+import (
+	"crypto/rand"
+	"encoding/base64"
+	"fmt"
+	"html/template"
+	"net"
+	"net/http"
+	"net/url"
+	"os"
+	"os/exec"
+	"strings"
+
+	"veyron.io/veyron/veyron/services/identity/googleoauth"
+	"veyron.io/veyron/veyron2/vlog"
+)
+
+func getMacaroonForBlessRPC(blessServerURL string, blessedChan <-chan string) (<-chan string, error) {
+	// Setup a HTTP server to recieve a blessing macaroon from the identity server.
+	// Steps:
+	// 1. Generate a state token to be included in the HTTP request
+	//    (though, arguably, the random port assigment for the HTTP server is enough
+	//    for XSRF protection)
+	// 2. Setup a HTTP server which will receive the final blessing macaroon from the id server.
+	// 3. Print out the link (to start the auth flow) for the user to click.
+	// 4. Return the macaroon and the rpc object name(where to make the MacaroonBlesser.Bless RPC call)
+	//    in the "result" channel.
+	var stateBuf [32]byte
+	if _, err := rand.Read(stateBuf[:]); err != nil {
+		return nil, fmt.Errorf("failed to generate state token for OAuth: %v", err)
+	}
+	state := base64.URLEncoding.EncodeToString(stateBuf[:])
+
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		return nil, fmt.Errorf("failed to setup authorization code interception server: %v", err)
+	}
+	result := make(chan string)
+
+	redirectURL := fmt.Sprintf("http://%s/macaroon", ln.Addr())
+	http.HandleFunc("/macaroon", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "text/html")
+		tmplArgs := struct {
+			Blessings, ErrShort, ErrLong string
+		}{}
+		defer func() {
+			if len(tmplArgs.ErrShort) > 0 {
+				w.WriteHeader(http.StatusBadRequest)
+			}
+			if err := tmpl.Execute(w, tmplArgs); err != nil {
+				vlog.Info("Failed to render template:", err)
+			}
+		}()
+
+		toolState := r.FormValue("state")
+		if toolState != state {
+			tmplArgs.ErrShort = "Unexpected request"
+			tmplArgs.ErrLong = "Mismatched state parameter. Possible cross-site-request-forgery?"
+			return
+		}
+		result <- r.FormValue("macaroon")
+		result <- r.FormValue("object_name")
+		defer close(result)
+		blessed, ok := <-blessedChan
+		if !ok {
+			tmplArgs.ErrShort = "No blessings received"
+			tmplArgs.ErrLong = "Unable to obtain blessings from the Veyron service"
+			return
+		}
+		tmplArgs.Blessings = blessed
+		ln.Close()
+	})
+	go http.Serve(ln, nil)
+
+	// Print the link to start the flow.
+	url, err := seekBlessingsURL(blessServerURL, redirectURL, state)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create seekBlessingsURL: %s", err)
+	}
+	fmt.Fprintln(os.Stderr, "Please visit the following URL to seek blessings:")
+	fmt.Fprintln(os.Stderr, url)
+	// Make an attempt to start the browser as a convenience.
+	// If it fails, doesn't matter - the client can see the URL printed above.
+	// Use exec.Command().Start instead of exec.Command().Run since there is no
+	// need to wait for the command to return (and indeed on some window managers,
+	// the command will not exit until the browser is closed).
+	if len(openCommand) != 0 {
+		exec.Command(openCommand, url).Start()
+	}
+	return result, nil
+}
+
+func seekBlessingsURL(blessServerURL, redirectURL, state string) (string, error) {
+	baseURL, err := url.Parse(joinURL(blessServerURL, googleoauth.SeekBlessingsRoute))
+	if err != nil {
+		return "", fmt.Errorf("failed to parse url: %v", err)
+	}
+	params := url.Values{}
+	params.Add("redirect_url", redirectURL)
+	params.Add("state", state)
+	baseURL.RawQuery = params.Encode()
+	return baseURL.String(), nil
+}
+
+func joinURL(baseURL, suffix string) string {
+	if !strings.HasSuffix(baseURL, "/") {
+		baseURL += "/"
+	}
+	return baseURL + suffix
+}
+
+var tmpl = template.Must(template.New("name").Parse(`<!doctype html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>Veyron Identity: Google</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
+{{if .Blessings}}
+<!--Attempt to close the window. Though this script does not work on many browser configurations-->
+<script type="text/javascript">window.close();</script>
+{{end}}
+</head>
+<body>
+<div class="container">
+{{if .ErrShort}}
+<h1><span class="label label-danger">error</span>{{.ErrShort}}</h1>
+<div class="well">{{.ErrLong}}</div>
+{{else}}
+<h3>Received blessings: <tt>{{.Blessings}}</tt></h3>
+{{end}}
+</div>
+</body>
+</html>`))
diff --git a/tools/principal/main.go b/tools/principal/main.go
index 51a9181..a0a61c1 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -10,10 +10,12 @@
 	"time"
 
 	"veyron.io/veyron/veyron/lib/cmdline"
+	"veyron.io/veyron/veyron/services/identity"
 	"veyron.io/veyron/veyron/services/identity/util"
 
 	"veyron.io/veyron/veyron2/rt"
 	"veyron.io/veyron/veyron2/security"
+	"veyron.io/veyron/veyron2/vdl/vdlutil"
 )
 
 var (
@@ -21,6 +23,31 @@
 	flagBlessFor   time.Duration
 	flagAddForPeer string
 
+	// Flags for the "seekblessing" command
+	flagSeekBlessingFrom string
+	flagSkipSetDefault   bool
+	flagForPeer          string
+
+	cmdDump = &cmdline.Command{
+		Name:  "dump",
+		Short: "Dump out information about the principal",
+		Long: `
+Dumps out information about the principal specified by the environment
+(VEYRON_CREDENTIALS) that this tool is running in.
+`,
+		Run: func(cmd *cmdline.Command, args []string) error {
+			p := rt.R().Principal()
+			fmt.Printf("Public key : %v\n", p.PublicKey())
+			fmt.Println("")
+			fmt.Println("---------------- BlessingStore ----------------")
+			fmt.Printf("%v", p.BlessingStore().DebugString())
+			fmt.Println("")
+			fmt.Println("---------------- BlessingRoots ----------------")
+			fmt.Printf("%v", p.Roots().DebugString())
+			return nil
+		},
+	}
+
 	cmdPrint = &cmdline.Command{
 		Name:  "print",
 		Short: "Print out information about the provided blessing",
@@ -195,6 +222,67 @@
 			return nil
 		},
 	}
+
+	cmdSeekBlessings = &cmdline.Command{
+		Name:  "seekblessings",
+		Short: "Seek blessings from a web-based Veyron blesser",
+		Long: `
+Seeks blessings from a web-based Veyron blesser which
+requires the caller to first authenticate with Google using OAuth. Simply
+run the command to see what happens.
+
+The blessings are sought for the principal specified by the environment
+(VEYRON_CREDENTIALS) that this tool is running in.
+
+The blessings obtained are set as default, unless a --skip_set_default flag
+is provided, and are also set for sharing with all peers, unless a more
+specific peer pattern is provided using the --for_peer flag.
+`,
+		Run: func(cmd *cmdline.Command, args []string) error {
+			blessedChan := make(chan string)
+			defer close(blessedChan)
+			macaroonChan, err := getMacaroonForBlessRPC(flagSeekBlessingFrom, blessedChan)
+			if err != nil {
+				return fmt.Errorf("failed to get macaroon from Veyron blesser: %v", err)
+			}
+			macaroon := <-macaroonChan
+			service := <-macaroonChan
+
+			ctx, cancel := rt.R().NewContext().WithTimeout(time.Minute)
+			defer cancel()
+
+			var reply vdlutil.Any
+			blesser, err := identity.BindMacaroonBlesser(service)
+			if err == nil {
+				reply, err = blesser.Bless(ctx, macaroon)
+			}
+			if err != nil {
+				return fmt.Errorf("failed to get blessing from %q: %v", service, err)
+			}
+			wire, ok := reply.(security.WireBlessings)
+			if !ok {
+				return fmt.Errorf("received %T, want security.WireBlessings", reply)
+			}
+			blessings, err := security.NewBlessings(wire)
+			if err != nil {
+				return fmt.Errorf("failed to construct Blessings object from wire data: %v", err)
+			}
+			blessedChan <- fmt.Sprint(blessings)
+			// Wait for getTokenForBlessRPC to clean up:
+			<-macaroonChan
+
+			if !flagSkipSetDefault {
+				if err := rt.R().Principal().BlessingStore().SetDefault(blessings); err != nil {
+					return fmt.Errorf("failed to set blessings %v as default: %v", blessings, err)
+				}
+			}
+			pattern := security.BlessingPattern(flagForPeer)
+			if _, err := rt.R().Principal().BlessingStore().Set(blessings, pattern); err != nil {
+				return fmt.Errorf("failed to set blessings %v for peers %v: %v", blessings, pattern, err)
+			}
+			return dumpBlessings(blessings)
+		},
+	}
 )
 
 func main() {
@@ -205,6 +293,9 @@
 	}
 	rt.Init()
 	cmdBlessSelf.Flags.DurationVar(&flagBlessFor, "for", 0*time.Hour, "Expiry time of Blessing (optional)")
+	cmdSeekBlessings.Flags.StringVar(&flagSeekBlessingFrom, "from", "https://proxy.envyor.com:8125/google", "URL to use to begin the seek blessings process")
+	cmdSeekBlessings.Flags.BoolVar(&flagSkipSetDefault, "skip_set_default", false, "flag to indicate that the blessings obtained from the Veyron blesser must not be set as default on the principals's blessing store")
+	cmdSeekBlessings.Flags.StringVar(&flagForPeer, "for_peer", "...", "pattern to be used while setting the blessings obtained from the Veyron blesser on the principal's blessing store")
 
 	(&cmdline.Command{
 		Name:  "principal",
@@ -215,7 +306,7 @@
 
 All objects are printed using base64-VOM-encoding.
 `,
-		Children: []*cmdline.Command{cmdPrint, cmdBlessSelf, cmdDefault, cmdForPeer, cmdSetDefault, cmdSet},
+		Children: []*cmdline.Command{cmdDump, cmdPrint, cmdBlessSelf, cmdDefault, cmdForPeer, cmdSetDefault, cmdSet, cmdSeekBlessings},
 	}).Main()
 }
 
diff --git a/tools/principal/main_darwin.go b/tools/principal/main_darwin.go
new file mode 100644
index 0000000..bceafd2
--- /dev/null
+++ b/tools/principal/main_darwin.go
@@ -0,0 +1,5 @@
+// +build darwin
+
+package main
+
+const openCommand = "open"
diff --git a/tools/principal/main_linux.go b/tools/principal/main_linux.go
new file mode 100644
index 0000000..cb73c65
--- /dev/null
+++ b/tools/principal/main_linux.go
@@ -0,0 +1,5 @@
+// +build linux
+
+package main
+
+const openCommand = "xdg-open"
diff --git a/tools/principal/main_nacl.go b/tools/principal/main_nacl.go
new file mode 100644
index 0000000..9dea3b5
--- /dev/null
+++ b/tools/principal/main_nacl.go
@@ -0,0 +1,3 @@
+package main
+
+const openCommand = ""
diff --git a/tools/principal/test.sh b/tools/principal/test.sh
index 3041116..770abb3 100755
--- a/tools/principal/test.sh
+++ b/tools/principal/test.sh
@@ -3,6 +3,8 @@
 # Test the principal command-line tool.
 #
 # This tests most operations of the principal command-line tool.
+# Not the "seekblessing" command yet, since that requires
+# starting a separate server.
 
 source "${VEYRON_ROOT}/scripts/lib/shell_test.sh"
 
@@ -23,10 +25,11 @@
   # Set VEYRON_CREDENTIALS.
   export VEYRON_CREDENTIALS="${WORKDIR}"
 
-  ./principal store.default >/dev/null || shell_test::fail "line ${LINENO}: store.default failed"
-  ./principal store.forpeer >/dev/null || shell_test::fail "line ${LINENO}: store.forpeer failed"
+  ./principal dump >/dev/null || shell_test::fail "line ${LINENO}: dump failed"
   ./principal blessself >/dev/null || shell_test::fail "line ${LINENO}: blessself failed"
   ./principal blessself alice >alice || shell_test::fail "line ${LINENO}: blessself alice failed"
+  ./principal store.default >/dev/null || shell_test::fail "line ${LINENO}: store.default failed"
+  ./principal store.forpeer >/dev/null || shell_test::fail "line ${LINENO}: store.forpeer failed"
 
   # Test print
   local GOT=$(./principal print alice | extractBlessings)