naming,security: Server authorization via trusted mounttables
(Part 2 of 2).

Details in commit 4312a8df4ba0cc5e77a9202ff464bd06a84928e4
(https://vanadium-review.googlesource.com/#/c/2971/)

This commit represents steps (c) & (d) in the commit description
referenced above.

Change-Id: Ifa28de3a49c6be5ad07f5ae37e4080f2ff73615e
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index d650d92..5e0815e 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -426,7 +426,6 @@
 // the servers that were successfully connected to and authorized).
 func (c *client) tryCall(ctx *context.T, name, method string, args []interface{}, opts []ipc.CallOpt) (ipc.Call, verror.ActionCode, error) {
 	var resolved *naming.MountEntry
-	var pattern security.BlessingPattern
 	var err error
 	if resolved, err = c.ns.Resolve(ctx, name, getResolveOpts(opts)...); err != nil {
 		vlog.Errorf("Resolve: %v", err)
@@ -438,7 +437,6 @@
 		}
 		return nil, verror.NoRetry, verror.New(verror.ErrNoServers, ctx, name, err)
 	} else {
-		pattern = security.BlessingPattern(resolved.Pattern)
 		if len(resolved.Servers) == 0 {
 			return nil, verror.RetryRefetch, verror.New(verror.ErrNoServers, ctx, name)
 		}
@@ -448,7 +446,7 @@
 		}
 	}
 
-	// servers is now orderd by the priority heurestic implemented in
+	// servers is now ordered by the priority heurestic implemented in
 	// filterAndOrderServers.
 	//
 	// Try to connect to all servers in parallel.  Provide sufficient
@@ -519,7 +517,8 @@
 			if r.flow.LocalPrincipal() != nil {
 				// Validate caveats on the server's identity for the context associated with this call.
 				var err error
-				if serverB, grantedB, err = c.authorizeServer(ctx, r.flow, name, method, pattern, opts); err != nil {
+				patterns := resolved.Servers[r.index].BlessingPatterns
+				if serverB, grantedB, err = c.authorizeServer(ctx, r.flow, name, method, patterns, opts); err != nil {
 					r.err = verror.New(errNotTrusted, ctx, name, r.flow.RemoteBlessings(), err)
 					vlog.VI(2).Infof("ipc: err: %s", r.err)
 					r.flow.Close()
@@ -642,7 +641,7 @@
 // the RPC name.method for the client (local end of the flow). It returns the blessings at the
 // server that are authorized for this purpose and any blessings that are to be granted to
 // the server (via ipc.Granter implementations in opts.)
-func (c *client) authorizeServer(ctx *context.T, flow stream.Flow, name, method string, serverPattern security.BlessingPattern, opts []ipc.CallOpt) (serverBlessings []string, grantedBlessings security.Blessings, err error) {
+func (c *client) authorizeServer(ctx *context.T, flow stream.Flow, name, method string, serverPatterns []string, opts []ipc.CallOpt) (serverBlessings []string, grantedBlessings security.Blessings, err error) {
 	if flow.RemoteBlessings() == nil {
 		return nil, nil, verror.New(errNoBlessings, ctx)
 	}
@@ -655,16 +654,9 @@
 		RemoteDischarges: flow.RemoteDischarges(),
 		Method:           method,
 		Suffix:           name})
-	serverBlessings, serverErr := flow.RemoteBlessings().ForContext(ctxt)
-	if serverPattern != "" {
-		if !serverPattern.MatchedBy(serverBlessings...) {
-			return nil, nil, verror.New(errAuthNoPatternMatch, ctx, serverBlessings, serverPattern, serverErr)
-		}
-	} else if enableSecureServerAuth {
-		if err := (defaultAuthorizer{}).Authorize(ctxt); err != nil {
-			return nil, nil, verror.New(errDefaultAuthDenied, ctx, serverBlessings)
-		}
-	}
+	var rejectedBlessings []security.RejectedBlessing
+	serverBlessings, rejectedBlessings = flow.RemoteBlessings().ForContext(ctxt)
+	var ignorePatterns bool
 	for _, o := range opts {
 		switch v := o.(type) {
 		case options.ServerPublicKey:
@@ -682,6 +674,8 @@
 			if !allowed {
 				return nil, nil, verror.New(errAuthServerNotAllowed, ctx, v, serverBlessings)
 			}
+		case options.SkipResolveAuthorization:
+			ignorePatterns = true
 		case ipc.Granter:
 			if b, err := v.Grant(flow.RemoteBlessings()); err != nil {
 				return nil, nil, verror.New(errBlessingGrant, ctx, serverBlessings, err)
@@ -690,6 +684,22 @@
 			}
 		}
 	}
+	if len(serverPatterns) > 0 && !ignorePatterns {
+		matched := false
+		for _, p := range serverPatterns {
+			if security.BlessingPattern(p).MatchedBy(serverBlessings...) {
+				matched = true
+				break
+			}
+		}
+		if !matched {
+			return nil, nil, verror.New(errAuthNoPatternMatch, ctx, serverBlessings, serverPatterns, rejectedBlessings)
+		}
+	} else if enableSecureServerAuth && !ignorePatterns {
+		if err := (defaultAuthorizer{}).Authorize(ctxt); err != nil {
+			return nil, nil, verror.New(errDefaultAuthDenied, ctx, serverBlessings)
+		}
+	}
 	return serverBlessings, grantedBlessings, nil
 }
 
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 2a184ba..e5ae443 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -239,9 +239,6 @@
 	if err := server.ServeDispatcher(name, disp); err != nil {
 		t.Errorf("server.ServeDispatcher failed: %v", err)
 	}
-	if err := server.AddName(name); err != nil {
-		t.Errorf("server.AddName for discharger failed: %v", err)
-	}
 
 	status := server.Status()
 	if got, want := endpointsToStrings(status.Endpoints), endpointsToStrings(eps); !reflect.DeepEqual(got, want) {
@@ -271,7 +268,7 @@
 func verifyMountMissing(t *testing.T, ns naming.Namespace, name string) {
 	if me, err := ns.Resolve(testContext(), name); err == nil {
 		names := me.Names()
-		t.Errorf("%s: %s not supposed to be found in mounttable; got %d servers instead: %v", loc(1), name, len(names), names)
+		t.Errorf("%s: %s not supposed to be found in mounttable; got %d servers instead: %v (%+v)", loc(1), name, len(names), names, me)
 	}
 }
 
@@ -464,7 +461,7 @@
 		}{
 			// Client accepts talking to the server only if the
 			// server's blessings match the provided pattern
-			{bServer, "mountpoint/server", nil, noErrID, ""},
+			{bServer, "[...]mountpoint/server", nil, noErrID, ""},
 			{bServer, "[root/server]mountpoint/server", nil, noErrID, ""},
 			{bServer, "[root/otherserver]mountpoint/server", nil, verror.ErrNotTrusted, nameErr},
 			{bServer, "[otherroot/server]mountpoint/server", nil, verror.ErrNotTrusted, nameErr},
@@ -472,24 +469,23 @@
 			// and, if the server's blessing has third-party
 			// caveats then the server provides appropriate
 			// discharges.
-			{bServerTPValid, "mountpoint/server", nil, noErrID, ""},
+			{bServerTPValid, "[...]mountpoint/server", nil, noErrID, ""},
 			{bServerTPValid, "[root/serverWithTPCaveats]mountpoint/server", nil, noErrID, ""},
 			{bServerTPValid, "[root/otherserver]mountpoint/server", nil, verror.ErrNotTrusted, nameErr},
 			{bServerTPValid, "[otherroot/server]mountpoint/server", nil, verror.ErrNotTrusted, nameErr},
 
 			// Client does not talk to a server that presents
 			// expired blessings (because the blessing store is
-			// configured to only talk to peers with blessings matching
-			// the pattern "root").
-			{bServerExpired, "mountpoint/server", nil, verror.ErrNotTrusted, vcErr},
+			// configured to only talk to root).
+			{bServerExpired, "[...]mountpoint/server", nil, verror.ErrNotTrusted, vcErr},
 
 			// Client does not talk to a server that fails to
 			// provide discharges for third-party caveats on the
 			// blessings presented by it.
-			{bServerTPExpired, "mountpoint/server", nil, verror.ErrNotTrusted, vcErr},
+			{bServerTPExpired, "[...]mountpoint/server", nil, verror.ErrNotTrusted, vcErr},
 
 			// Testing the AllowedServersPolicy option.
-			{bServer, "mountpoint/server", options.AllowedServersPolicy{"otherroot"}, verror.ErrNotTrusted, allowedErr},
+			{bServer, "[...]mountpoint/server", options.AllowedServersPolicy{"otherroot"}, verror.ErrNotTrusted, allowedErr},
 			{bServer, "[root/server]mountpoint/server", options.AllowedServersPolicy{"otherroot"}, verror.ErrNotTrusted, allowedErr},
 			{bServer, "[otherroot/server]mountpoint/server", options.AllowedServersPolicy{"root/server"}, verror.ErrNotTrusted, nameErr},
 			{bServer, "[root/server]mountpoint/server", options.AllowedServersPolicy{"root"}, noErrID, ""},
@@ -517,7 +513,7 @@
 	pclient.BlessingStore().Set(bless(pprovider, pclient, "client"), "root")
 
 	for i, test := range tests {
-		name := fmt.Sprintf("(Name:%q, Server:%q, Allowed:%v)", test.name, test.server, test.allowed)
+		name := fmt.Sprintf("(#%d: Name:%q, Server:%q, Allowed:%v)", i, test.name, test.server, test.allowed)
 		if err := pserver.BlessingStore().SetDefault(test.server); err != nil {
 			t.Fatalf("SetDefault failed on server's BlessingStore: %v", err)
 		}
@@ -537,7 +533,7 @@
 		}
 		call, err := client.StartCall(ctx, test.name, "Method", nil, opts...)
 		if !matchesErrorPattern(err, test.errID, test.err) {
-			t.Errorf(`%d: %s: client.StartCall: got error "%v", want to match "%v"`, i, name, err, test.err)
+			t.Errorf(`%s: client.StartCall: got error "%v", want to match "%v"`, name, err, test.err)
 		} else if call != nil {
 			blessings, proof := call.RemoteBlessings()
 			if proof == nil {
@@ -556,6 +552,63 @@
 	}
 }
 
+func TestServerManInTheMiddleAttack(t *testing.T) {
+	// Test scenario: A server mounts itself, but then some other service
+	// somehow "takes over" the endpoint, thus trying to steal traffic.
+
+	// Start up the attacker's server.
+	attacker, err := testInternalNewServer(
+		testContext(),
+		imanager.InternalNew(naming.FixedRoutingID(0xaaaaaaaaaaaaaaaa)),
+		// (To prevent the attacker for legitimately mounting on the
+		// namespace that the client will use, provide it with a
+		// different namespace).
+		tnaming.NewSimpleNamespace(),
+		vc.LocalPrincipal{tsecurity.NewPrincipal("attacker")})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if _, err := attacker.Listen(listenSpec); err != nil {
+		t.Fatal(err)
+	}
+	if err := attacker.ServeDispatcher("mountpoint/server", testServerDisp{&testServer{}}); err != nil {
+		t.Fatal(err)
+	}
+	var ep naming.Endpoint
+	if status := attacker.Status(); len(status.Endpoints) < 1 {
+		t.Fatalf("Attacker server does not have an endpoint: %+v", status)
+	} else {
+		ep = status.Endpoints[0]
+	}
+
+	// The legitimate server would have mounted the same endpoint on the
+	// namespace.
+	ns := tnaming.NewSimpleNamespace()
+	if err := ns.Mount(testContext(), "mountpoint/server", ep.Name(), time.Hour, naming.MountedServerBlessingsOpt{"server"}); err != nil {
+		t.Fatal(err)
+	}
+
+	// The RPC call should fail because the blessings presented by the
+	// (attacker's) server are not consistent with the ones registered in
+	// the mounttable trusted by the client.
+	client, err := InternalNewClient(
+		imanager.InternalNew(naming.FixedRoutingID(0xcccccccccccccccc)),
+		ns,
+		vc.LocalPrincipal{tsecurity.NewPrincipal("client")})
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer client.Close()
+	if _, err := client.StartCall(testContext(), "mountpoint/server", "Closure", nil); !verror.Is(err, verror.ErrNotTrusted.ID) {
+		t.Errorf("Got error %v (errorid=%v), want errorid=%v", err, verror.ErrorID(err), verror.ErrNotTrusted.ID)
+	}
+	// But the RPC should succeed if the client explicitly
+	// decided to skip server authorization.
+	if _, err := client.StartCall(testContext(), "mountpoint/server", "Closure", nil, options.SkipResolveAuthorization{}); err != nil {
+		t.Errorf("Unexpected error(%v) when skipping server authorization", err)
+	}
+}
+
 type websocketMode bool
 type closeSendMode bool
 
@@ -1440,7 +1493,7 @@
 	defer runServer("mountpoint/batman", options.ServerBlessings{batman}).Shutdown()
 	defer runServer("mountpoint/default").Shutdown()
 
-	// And finally, make and RPC and see that the client sees "batman"
+	// And finally, make an RPC and see that the client sees "batman"
 	runClient := func(server string) ([]string, error) {
 		smc := imanager.InternalNew(naming.FixedRoutingID(0xc))
 		defer smc.Shutdown()
diff --git a/runtimes/google/naming/namespace/all_test.go b/runtimes/google/naming/namespace/all_test.go
index 450f89f..ab41beb 100644
--- a/runtimes/google/naming/namespace/all_test.go
+++ b/runtimes/google/naming/namespace/all_test.go
@@ -1,6 +1,7 @@
 package namespace_test
 
 import (
+	"reflect"
 	"runtime"
 	"runtime/debug"
 	"sync"
@@ -30,11 +31,22 @@
 
 func createContexts(t *testing.T) (sc, c *context.T, cleanup func()) {
 	ctx, shutdown := testutil.InitForTest()
-	var err error
-	if sc, err = veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-blessing")); err != nil {
+	var (
+		err error
+		psc = tsecurity.NewPrincipal("sc")
+		pc  = tsecurity.NewPrincipal("c")
+	)
+	// Setup the principals so that they recognize each other.
+	if err := psc.AddToRoots(pc.BlessingStore().Default()); err != nil {
 		t.Fatal(err)
 	}
-	if c, err = veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-blessing")); err != nil {
+	if err := pc.AddToRoots(psc.BlessingStore().Default()); err != nil {
+		t.Fatal(err)
+	}
+	if sc, err = veyron2.SetPrincipal(ctx, psc); err != nil {
+		t.Fatal(err)
+	}
+	if c, err = veyron2.SetPrincipal(ctx, pc); err != nil {
 		t.Fatal(err)
 	}
 	return sc, c, shutdown
@@ -641,3 +653,89 @@
 	// After successful lookup it should be cached, so the pattern doesn't matter.
 	testResolveWithPattern(t, c, ns, name, naming.RootBlessingPatternOpt("root/foobar"), mts[mt2MP].name)
 }
+
+func TestAuthenticationDuringResolve(t *testing.T) {
+	ctx, shutdown := veyron2.Init()
+	defer shutdown()
+
+	var (
+		rootMtCtx, _ = veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal()) // root mounttable
+		mtCtx, _     = veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal()) // intermediate mounttable
+		serverCtx, _ = veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal()) // end server
+		clientCtx, _ = veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal()) // client process (doing Resolves).
+		idp          = tsecurity.NewIDProvider("idp")                      // identity provider
+		ep1          = naming.FormatEndpoint("tcp", "127.0.0.1:14141")
+
+		resolve = func(name string, opts ...naming.ResolveOpt) (*naming.MountEntry, error) {
+			return veyron2.GetNamespace(clientCtx).Resolve(clientCtx, name, opts...)
+		}
+
+		mount = func(name, server string, ttl time.Duration, opts ...naming.MountOpt) error {
+			return veyron2.GetNamespace(serverCtx).Mount(serverCtx, name, server, ttl, opts...)
+		}
+	)
+	// Setup default blessings for the processes.
+	idp.Bless(veyron2.GetPrincipal(rootMtCtx), "rootmt")
+	idp.Bless(veyron2.GetPrincipal(serverCtx), "server")
+	idp.Bless(veyron2.GetPrincipal(mtCtx), "childmt")
+	idp.Bless(veyron2.GetPrincipal(clientCtx), "client")
+
+	// Setup the namespace root for all the "processes".
+	rootmt := runMT(t, rootMtCtx, "")
+	for _, ctx := range []*context.T{mtCtx, serverCtx, clientCtx} {
+		veyron2.GetNamespace(ctx).SetRoots(rootmt.name)
+	}
+	// Disable caching in the client so that any Mount calls by the server
+	// are noticed immediately.
+	veyron2.GetNamespace(clientCtx).CacheCtl(naming.DisableCache(true))
+
+	// Server mounting without an explicitly specified MountedServerBlessingsOpt,
+	// will automatically fill the Default blessings in.
+	if err := mount("server", ep1, time.Minute); err != nil {
+		t.Error(err)
+	} else if e, err := resolve("server"); err != nil {
+		t.Error(err)
+	} else if len(e.Servers) != 1 {
+		t.Errorf("Got %v, wanted a single server", e.Servers)
+	} else if s := e.Servers[0]; s.Server != ep1 || len(s.BlessingPatterns) != 1 || s.BlessingPatterns[0] != "idp/server" {
+		t.Errorf("Got (%q, %v) want (%q, [%q])", s.Server, s.BlessingPatterns, ep1, "idp/server")
+	} else if e, err = resolve("[otherpattern]server"); err != nil {
+		// Resolving with the "[<pattern>]<OA>" syntax, then <pattern> wins.
+		t.Error(err)
+	} else if s = e.Servers[0]; s.Server != ep1 || len(s.BlessingPatterns) != 1 || s.BlessingPatterns[0] != "otherpattern" {
+		t.Errorf("Got (%q, %v) want (%q, [%q])", s.Server, s.BlessingPatterns, ep1, "otherpattern")
+	}
+	// If an option is explicitly specified, it should be respected.
+	if err := mount("server", ep1, time.Minute, naming.ReplaceMountOpt(true), naming.MountedServerBlessingsOpt{"b1", "b2"}); err != nil {
+		t.Error(err)
+	} else if e, err := resolve("server"); err != nil {
+		t.Error(err)
+	} else if len(e.Servers) != 1 {
+		t.Errorf("Got %v, wanted a single server", e.Servers)
+	} else if s, pats := e.Servers[0], []string{"b1", "b2"}; s.Server != ep1 || !reflect.DeepEqual(s.BlessingPatterns, pats) {
+		t.Errorf("Got (%q, %v) want (%q, %v)", s.Server, s.BlessingPatterns, ep1, pats)
+	}
+
+	// Intermediate mounttables should be authenticated.
+	// Simulate an "attacker" by changing the blessings presented by this
+	// intermediate mounttable (which will not be consistent with the
+	// blessing pattern in the mount entry). A subtle annoyance here: This
+	// "attack" is valid only until the child mounttable remounts itself.
+	// Currently this remounting period is set to 1 minute (publishPeriod
+	// in ipc/consts.go), but if that changes - then this test may need
+	// to change as well.
+	runMT(t, mtCtx, "mt")
+	attacker, err := veyron2.GetPrincipal(mtCtx).BlessSelf("attacker")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := mount("mt/server", ep1, time.Minute, naming.ReplaceMountOpt(true)); err != nil {
+		t.Error(err)
+	} else if err := veyron2.GetPrincipal(mtCtx).BlessingStore().SetDefault(attacker); err != nil {
+		t.Error(err)
+	} else if e, err := resolve("mt/server", options.SkipResolveAuthorization{}); err != nil {
+		t.Errorf("Resolve should succeed when skipping server authorization. Got (%v, %v)", e, err)
+	} else if e, err := resolve("mt/server"); !verror.Is(err, verror.ErrNotTrusted.ID) {
+		t.Errorf("Resolve should have failed with %q because an attacker has taken over the intermediate mounttable. Got (%+v, errorid=%q:%v)", verror.ErrNotTrusted.ID, e, verror.ErrorID(err), err)
+	}
+}
diff --git a/runtimes/google/naming/namespace/glob.go b/runtimes/google/naming/namespace/glob.go
index 495089b..3d81e58 100644
--- a/runtimes/google/naming/namespace/glob.go
+++ b/runtimes/google/naming/namespace/glob.go
@@ -224,9 +224,9 @@
 // Glob implements naming.MountTable.Glob.
 func (ns *namespace) Glob(ctx *context.T, pattern string) (chan interface{}, error) {
 	defer vlog.LogCall()()
-
 	// Root the pattern.  If we have no servers to query, give up.
-	e, patternWasRooted := ns.rootMountEntry(pattern)
+	// TODO(ashankar): Should not ignore the pattern on the end server?
+	e, _, patternWasRooted := ns.rootMountEntry(pattern)
 	if len(e.Servers) == 0 {
 		return nil, verror.New(naming.ErrNoMountTable, ctx)
 	}
diff --git a/runtimes/google/naming/namespace/glob_test.go b/runtimes/google/naming/namespace/glob_test.go
index c160ccf..6d51bd1 100644
--- a/runtimes/google/naming/namespace/glob_test.go
+++ b/runtimes/google/naming/namespace/glob_test.go
@@ -2,6 +2,8 @@
 
 import (
 	"testing"
+
+	"v.io/core/veyron2/security"
 )
 
 func TestDepth(t *testing.T) {
@@ -27,35 +29,38 @@
 }
 
 func TestSplitObjectName(t *testing.T) {
+	const notset = ""
 	cases := []struct {
-		input, mt, server, name string
+		input      string
+		mt, server security.BlessingPattern
+		name       string
 	}{
-		{"[foo/bar]", "", "foo/bar", ""},
-		{"[x/y]/", "x/y", "", "/"},
-		{"[foo]a", "", "foo", "a"},
-		{"[foo]/a", "foo", "", "/a"},
+		{"[foo/bar]", notset, "foo/bar", ""},
+		{"[x/y]/", "x/y", notset, "/"},
+		{"[foo]a", notset, "foo", "a"},
+		{"[foo]/a", "foo", notset, "/a"},
 		{"[foo]/a/[bar]", "foo", "bar", "/a"},
-		{"a/b", "", "", "a/b"},
-		{"[foo]a/b", "", "foo", "a/b"},
-		{"/a/b", "", "", "/a/b"},
-		{"[foo]/a/b", "foo", "", "/a/b"},
-		{"/a/[bar]b", "", "bar", "/a/b"},
+		{"a/b", notset, notset, "a/b"},
+		{"[foo]a/b", notset, "foo", "a/b"},
+		{"/a/b", notset, notset, "/a/b"},
+		{"[foo]/a/b", "foo", notset, "/a/b"},
+		{"/a/[bar]b", notset, "bar", "/a/b"},
 		{"[foo]/a/[bar]b", "foo", "bar", "/a/b"},
-		{"/a/b[foo]", "", "", "/a/b[foo]"},
-		{"/a/b/[foo]c", "", "", "/a/b/[foo]c"},
-		{"/[01:02::]:444", "", "", "/[01:02::]:444"},
-		{"[foo]/[01:02::]:444", "foo", "", "/[01:02::]:444"},
-		{"/[01:02::]:444/foo", "", "", "/[01:02::]:444/foo"},
-		{"[a]/[01:02::]:444/foo", "a", "", "/[01:02::]:444/foo"},
-		{"/[01:02::]:444/[b]foo", "", "b", "/[01:02::]:444/foo"},
+		{"/a/b[foo]", notset, notset, "/a/b[foo]"},
+		{"/a/b/[foo]c", notset, notset, "/a/b/[foo]c"},
+		{"/[01:02::]:444", notset, notset, "/[01:02::]:444"},
+		{"[foo]/[01:02::]:444", "foo", notset, "/[01:02::]:444"},
+		{"/[01:02::]:444/foo", notset, notset, "/[01:02::]:444/foo"},
+		{"[a]/[01:02::]:444/foo", "a", notset, "/[01:02::]:444/foo"},
+		{"/[01:02::]:444/[b]foo", notset, "b", "/[01:02::]:444/foo"},
 		{"[c]/[01:02::]:444/[d]foo", "c", "d", "/[01:02::]:444/foo"},
 	}
 	for _, c := range cases {
 		mt, server, name := splitObjectName(c.input)
-		if string(mt) != c.mt {
+		if mt != c.mt {
 			t.Errorf("%q: unexpected mt pattern: %q not %q", c.input, mt, c.mt)
 		}
-		if string(server) != c.server {
+		if server != c.server {
 			t.Errorf("%q: unexpected server pattern: %q not %q", c.input, server, c.server)
 		}
 		if name != c.name {
diff --git a/runtimes/google/naming/namespace/mount.go b/runtimes/google/naming/namespace/mount.go
index 0cab494..55a5027 100644
--- a/runtimes/google/naming/namespace/mount.go
+++ b/runtimes/google/naming/namespace/mount.go
@@ -1,6 +1,7 @@
 package namespace
 
 import (
+	"fmt"
 	"time"
 
 	inaming "v.io/core/veyron/runtimes/google/naming"
@@ -10,6 +11,7 @@
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/naming"
 	"v.io/core/veyron2/options"
+	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/vlog"
 )
 
@@ -19,10 +21,10 @@
 }
 
 // mountIntoMountTable mounts a single server into a single mount table.
-func mountIntoMountTable(ctx *context.T, client ipc.Client, name, server string, ttl time.Duration, flags naming.MountFlag, id string) (s status) {
+func mountIntoMountTable(ctx *context.T, client ipc.Client, name, server string, patterns []security.BlessingPattern, ttl time.Duration, flags naming.MountFlag, id string) (s status) {
 	s.id = id
 	ctx, _ = context.WithTimeout(ctx, callTimeout)
-	call, err := client.StartCall(ctx, name, "Mount", []interface{}{server, uint32(ttl.Seconds()), flags}, options.NoResolve{})
+	call, err := client.StartCall(ctx, name, "MountX", []interface{}{server, patterns, uint32(ttl.Seconds()), flags}, options.NoResolve{})
 	s.err = err
 	if err != nil {
 		return
@@ -107,6 +109,7 @@
 	defer vlog.LogCall()()
 
 	var flags naming.MountFlag
+	var patterns []string
 	for _, o := range opts {
 		// NB: used a switch since we'll be adding more options.
 		switch v := o.(type) {
@@ -118,17 +121,32 @@
 			if v {
 				flags |= naming.MountFlag(naming.MT)
 			}
+		case naming.MountedServerBlessingsOpt:
+			patterns = []string(v)
 		}
 	}
+	if len(patterns) == 0 {
+		// No patterns explicitly provided. Take the conservative
+		// approach that the server being mounted is run by this local
+		// process.
+		p := veyron2.GetPrincipal(ctx)
+		b := p.BlessingStore().Default()
+		if b == nil {
+			return fmt.Errorf("must provide a MountedServerBlessingsOpt")
+		}
+		for str, _ := range p.BlessingsInfo(b) {
+			patterns = append(patterns, str)
+		}
+		vlog.VI(2).Infof("Mount(%s, %s): No MountedServerBlessingsOpt provided using %v", name, server, patterns)
+	}
 
 	client := veyron2.GetClient(ctx)
-
 	// Mount the server in all the returned mount tables.
 	f := func(ctx *context.T, mt, id string) status {
-		return mountIntoMountTable(ctx, client, mt, server, ttl, flags, id)
+		return mountIntoMountTable(ctx, client, mt, server, str2pattern(patterns), ttl, flags, id)
 	}
 	err := ns.dispatch(ctx, name, f)
-	vlog.VI(1).Infof("Mount(%s, %s) -> %v", name, server, err)
+	vlog.VI(1).Infof("Mount(%s, %q, %v) -> %v", name, server, patterns, err)
 	return err
 }
 
@@ -143,3 +161,11 @@
 	vlog.VI(1).Infof("Unmount(%s, %s) -> %v", name, server, err)
 	return err
 }
+
+func str2pattern(strs []string) (ret []security.BlessingPattern) {
+	ret = make([]security.BlessingPattern, len(strs))
+	for i, s := range strs {
+		ret[i] = security.BlessingPattern(s)
+	}
+	return
+}
diff --git a/runtimes/google/naming/namespace/namespace.go b/runtimes/google/naming/namespace/namespace.go
index 612664b..7b176ac 100644
--- a/runtimes/google/naming/namespace/namespace.go
+++ b/runtimes/google/naming/namespace/namespace.go
@@ -119,11 +119,18 @@
 }
 
 // rootMountEntry 'roots' a name creating a mount entry for the name.
-func (ns *namespace) rootMountEntry(name string) (*naming.MountEntry, bool) {
+//
+// Returns:
+// (1) MountEntry
+// (2) The BlessingPattern that the end servers are expected to match
+//     (empty string if no such pattern).
+// (3) Whether "name" is a rooted name or not (if not, the namespace roots
+//     configured in "ns" will be used).
+func (ns *namespace) rootMountEntry(name string, opts ...naming.ResolveOpt) (*naming.MountEntry, security.BlessingPattern, bool) {
 	name = naming.Clean(name)
 	_, objPattern, name := splitObjectName(name)
+	mtPattern := getRootPattern(opts)
 	e := new(naming.MountEntry)
-	e.Pattern = string(objPattern)
 	expiration := time.Now().Add(time.Hour) // plenty of time for a call
 	address, suffix := naming.SplitAddressName(name)
 	if len(address) == 0 {
@@ -132,9 +139,14 @@
 		ns.RLock()
 		defer ns.RUnlock()
 		for _, r := range ns.roots {
-			e.Servers = append(e.Servers, naming.MountedServer{Server: r, Expires: expiration})
+			// TODO(ashankar): Configured namespace roots should also include the pattern?
+			server := naming.MountedServer{Server: r, Expires: expiration}
+			if len(mtPattern) > 0 {
+				server.BlessingPatterns = []string{mtPattern}
+			}
+			e.Servers = append(e.Servers, server)
 		}
-		return e, false
+		return e, objPattern, false
 	}
 	servesMT := true
 	if ep, err := inaming.NewEndpoint(address); err == nil {
@@ -142,8 +154,12 @@
 	}
 	e.SetServesMountTable(servesMT)
 	e.Name = suffix
-	e.Servers = append(e.Servers, naming.MountedServer{Server: naming.JoinAddressName(address, ""), Expires: expiration})
-	return e, true
+	server := naming.MountedServer{Server: naming.JoinAddressName(address, ""), Expires: expiration}
+	if servesMT && len(mtPattern) > 0 {
+		server.BlessingPatterns = []string{string(mtPattern)}
+	}
+	e.Servers = []naming.MountedServer{server}
+	return e, objPattern, true
 }
 
 // notAnMT returns true if the error indicates this isn't a mounttable server.
@@ -194,6 +210,15 @@
 	return nil
 }
 
+// TODO(ribrdb,ashankar): This is exported only for the mock namespace to share
+// functionality.  Refactor this sharing and do not use this function outside
+// the one place it is being used to implement a mock namespace.
+func InternalSplitObjectName(name string) (p security.BlessingPattern, n string) {
+	_, p, n = splitObjectName(name)
+	return
+}
+
+// TODO(ashankar,ribrdb): Get rid of "mtPattern"?
 func splitObjectName(name string) (mtPattern, serverPattern security.BlessingPattern, objectName string) {
 	objectName = name
 	match := serverPatternRegexp.FindSubmatch([]byte(name))
@@ -218,3 +243,12 @@
 	}
 	return
 }
+
+func getRootPattern(opts []naming.ResolveOpt) string {
+	for _, opt := range opts {
+		if pattern, ok := opt.(naming.RootBlessingPatternOpt); ok {
+			return string(pattern)
+		}
+	}
+	return ""
+}
diff --git a/runtimes/google/naming/namespace/resolve.go b/runtimes/google/naming/namespace/resolve.go
index 5a91c14..8c4bfec 100644
--- a/runtimes/google/naming/namespace/resolve.go
+++ b/runtimes/google/naming/namespace/resolve.go
@@ -2,7 +2,6 @@
 
 import (
 	"errors"
-	"fmt"
 	"runtime"
 
 	"v.io/core/veyron2"
@@ -10,29 +9,29 @@
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/naming"
 	"v.io/core/veyron2/options"
+	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/verror"
 	"v.io/core/veyron2/vlog"
 )
 
-func (ns *namespace) resolveAgainstMountTable(ctx *context.T, client ipc.Client, e *naming.MountEntry, pattern string, opts ...ipc.CallOpt) (*naming.MountEntry, error) {
+func (ns *namespace) resolveAgainstMountTable(ctx *context.T, client ipc.Client, e *naming.MountEntry, opts ...ipc.CallOpt) (*naming.MountEntry, error) {
 	// Try each server till one answers.
 	finalErr := errors.New("no servers to resolve query")
+	skipServerAuth := skipServerAuthorization(opts)
+	opts = append(opts, options.NoResolve{})
 	for _, s := range e.Servers {
-		var pattern_and_name string
 		name := naming.JoinAddressName(s.Server, e.Name)
-		if pattern != "" {
-			pattern_and_name = naming.JoinAddressName(s.Server, fmt.Sprintf("[%s]%s", pattern, e.Name))
-		} else {
-			pattern_and_name = name
-		}
 		// First check the cache.
 		if ne, err := ns.resolutionCache.lookup(name); err == nil {
 			vlog.VI(2).Infof("resolveAMT %s from cache -> %v", name, convertServersToStrings(ne.Servers, ne.Name))
 			return &ne, nil
 		}
 		// Not in cache, call the real server.
+		if !skipServerAuth {
+			opts = setAllowedServers(opts, s.BlessingPatterns)
+		}
 		callCtx, _ := context.WithTimeout(ctx, callTimeout)
-		call, err := client.StartCall(callCtx, pattern_and_name, "ResolveStep", nil, append(opts, options.NoResolve{})...)
+		call, err := client.StartCall(callCtx, name, "ResolveStep", nil, opts...)
 		if err != nil {
 			finalErr = err
 			vlog.VI(2).Infof("ResolveStep.StartCall %s failed: %s", name, err)
@@ -71,19 +70,19 @@
 // Resolve implements veyron2/naming.Namespace.
 func (ns *namespace) Resolve(ctx *context.T, name string, opts ...naming.ResolveOpt) (*naming.MountEntry, error) {
 	defer vlog.LogCall()()
-	e, _ := ns.rootMountEntry(name)
+	e, objPattern, _ := ns.rootMountEntry(name, opts...)
 	if vlog.V(2) {
 		_, file, line, _ := runtime.Caller(1)
 		vlog.Infof("Resolve(%s) called from %s:%d", name, file, line)
 		vlog.Infof("Resolve(%s) -> rootMountEntry %v", name, *e)
 	}
 	if skipResolve(opts) {
+		setBlessingPatterns(e, objPattern)
 		return e, nil
 	}
 	if len(e.Servers) == 0 {
 		return nil, verror.New(naming.ErrNoSuchName, ctx, name)
 	}
-	pattern := getRootPattern(opts)
 	client := veyron2.GetClient(ctx)
 	callOpts := getCallOpts(opts)
 
@@ -91,15 +90,17 @@
 	for remaining := ns.maxResolveDepth; remaining > 0; remaining-- {
 		vlog.VI(2).Infof("Resolve(%s) loop %v", name, *e)
 		if !e.ServesMountTable() || terminal(e) {
+			setBlessingPatterns(e, objPattern)
 			vlog.VI(1).Infof("Resolve(%s) -> %v", name, *e)
 			return e, nil
 		}
 		var err error
 		curr := e
-		if e, err = ns.resolveAgainstMountTable(ctx, client, curr, pattern, callOpts...); err != nil {
+		if e, err = ns.resolveAgainstMountTable(ctx, client, curr, callOpts...); err != nil {
 			// Lots of reasons why another error can happen.  We are trying
 			// to single out "this isn't a mount table".
 			if notAnMT(err) {
+				setBlessingPatterns(curr, objPattern)
 				vlog.VI(1).Infof("Resolve(%s) -> %v", name, curr)
 				return curr, nil
 			}
@@ -109,7 +110,6 @@
 			vlog.VI(1).Infof("Resolve(%s) -> (%s: %v)", err, name, curr)
 			return nil, err
 		}
-		pattern = ""
 	}
 	return nil, verror.New(naming.ErrResolutionDepthExceeded, ctx)
 }
@@ -117,7 +117,7 @@
 // ResolveToMountTable implements veyron2/naming.Namespace.
 func (ns *namespace) ResolveToMountTable(ctx *context.T, name string, opts ...naming.ResolveOpt) (*naming.MountEntry, error) {
 	defer vlog.LogCall()()
-	e, _ := ns.rootMountEntry(name)
+	e, _, _ := ns.rootMountEntry(name, opts...)
 	if vlog.V(2) {
 		_, file, line, _ := runtime.Caller(1)
 		vlog.Infof("ResolveToMountTable(%s) called from %s:%d", name, file, line)
@@ -126,7 +126,6 @@
 	if len(e.Servers) == 0 {
 		return nil, verror.New(naming.ErrNoMountTable, ctx)
 	}
-	pattern := getRootPattern(opts)
 	callOpts := getCallOpts(opts)
 	client := veyron2.GetClient(ctx)
 	last := e
@@ -139,7 +138,7 @@
 			vlog.VI(1).Infof("ResolveToMountTable(%s) -> %v", name, last)
 			return last, nil
 		}
-		if e, err = ns.resolveAgainstMountTable(ctx, client, e, pattern, callOpts...); err != nil {
+		if e, err = ns.resolveAgainstMountTable(ctx, client, e, callOpts...); err != nil {
 			if verror.Is(err, naming.ErrNoSuchNameRoot.ID) {
 				vlog.VI(1).Infof("ResolveToMountTable(%s) -> %v (NoSuchRoot: %v)", name, last, curr)
 				return last, nil
@@ -161,7 +160,6 @@
 			return nil, err
 		}
 		last = curr
-		pattern = ""
 	}
 	return nil, verror.New(naming.ErrResolutionDepthExceeded, ctx)
 }
@@ -199,15 +197,6 @@
 	return false
 }
 
-func getRootPattern(opts []naming.ResolveOpt) string {
-	for _, opt := range opts {
-		if pattern, ok := opt.(naming.RootBlessingPatternOpt); ok {
-			return string(pattern)
-		}
-	}
-	return ""
-}
-
 func getCallOpts(opts []naming.ResolveOpt) []ipc.CallOpt {
 	var out []ipc.CallOpt
 	for _, o := range opts {
@@ -217,3 +206,37 @@
 	}
 	return out
 }
+
+// setBlessingPatterns overrides e.Servers.BlessingPatterns with p if p is
+// non-empty. This will typically be the case for end servers (i.e., not
+// mounttables) where the client explicitly specified a blessing pattern and
+// thus explicitly chose to ignore the patterns from the MountEntry.
+func setBlessingPatterns(e *naming.MountEntry, p security.BlessingPattern) {
+	if len(p) == 0 {
+		return
+	}
+	slice := []string{string(p)}
+	for idx, _ := range e.Servers {
+		e.Servers[idx].BlessingPatterns = slice
+	}
+}
+
+func setAllowedServers(opts []ipc.CallOpt, patterns []string) []ipc.CallOpt {
+	if len(patterns) == 0 {
+		return opts
+	}
+	p := make(options.AllowedServersPolicy, len(patterns))
+	for i, v := range patterns {
+		p[i] = security.BlessingPattern(v)
+	}
+	return append(opts, p)
+}
+
+func skipServerAuthorization(opts []ipc.CallOpt) bool {
+	for _, o := range opts {
+		if _, ok := o.(options.SkipResolveAuthorization); ok {
+			return true
+		}
+	}
+	return false
+}
diff --git a/runtimes/google/naming/namespace/stub.go b/runtimes/google/naming/namespace/stub.go
index 0574e2c..a513e56 100644
--- a/runtimes/google/naming/namespace/stub.go
+++ b/runtimes/google/naming/namespace/stub.go
@@ -27,7 +27,7 @@
 			s.TTL = 32000000 // > 1 year
 		}
 		expires := time.Now().Add(time.Duration(s.TTL) * time.Second)
-		reply = append(reply, naming.MountedServer{Server: s.Server, Expires: expires})
+		reply = append(reply, naming.MountedServer{Server: s.Server, BlessingPatterns: s.BlessingPatterns, Expires: expires})
 	}
 	return reply
 }
diff --git a/runtimes/google/testing/mocks/naming/namespace.go b/runtimes/google/testing/mocks/naming/namespace.go
index 796c5e2..02927e8 100644
--- a/runtimes/google/testing/mocks/naming/namespace.go
+++ b/runtimes/google/testing/mocks/naming/namespace.go
@@ -8,7 +8,6 @@
 
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/naming"
-	"v.io/core/veyron2/options"
 	"v.io/core/veyron2/verror"
 	"v.io/core/veyron2/vlog"
 
@@ -23,18 +22,28 @@
 	if err != nil {
 		panic(err)
 	}
-	return &namespace{mounts: make(map[string][]string), ns: ns}
+	return &namespace{mounts: make(map[string]*naming.MountEntry), ns: ns}
 }
 
 // namespace is a simple partial implementation of naming.Namespace.
 type namespace struct {
 	sync.Mutex
-	mounts map[string][]string
+	mounts map[string]*naming.MountEntry
 	ns     naming.Namespace
 }
 
-func (ns *namespace) Mount(ctx *context.T, name, server string, _ time.Duration, _ ...naming.MountOpt) error {
+func (ns *namespace) Mount(ctx *context.T, name, server string, _ time.Duration, opts ...naming.MountOpt) error {
 	defer vlog.LogCall()()
+	// TODO(ashankar,p): There is a bunch of processing in the real
+	// namespace that is missing from this mock implementation and some of
+	// it is duplicated here.  Figure out a way to share more code with the
+	// real implementation?
+	var blessingpatterns []string
+	for _, o := range opts {
+		if v, ok := o.(naming.MountedServerBlessingsOpt); ok {
+			blessingpatterns = v
+		}
+	}
 	ns.Lock()
 	defer ns.Unlock()
 	for n, _ := range ns.mounts {
@@ -42,50 +51,74 @@
 			return fmt.Errorf("simple mount table does not allow names that are a prefix of each other")
 		}
 	}
-	ns.mounts[name] = append(ns.mounts[name], server)
+	e := ns.mounts[name]
+	if e == nil {
+		e = &naming.MountEntry{}
+		ns.mounts[name] = e
+	}
+	s := naming.MountedServer{
+		Server:           server,
+		BlessingPatterns: blessingpatterns,
+	}
+	e.Servers = append(e.Servers, s)
 	return nil
 }
 
 func (ns *namespace) Unmount(ctx *context.T, name, server string) error {
 	defer vlog.LogCall()()
-	var servers []string
 	ns.Lock()
 	defer ns.Unlock()
-	for _, s := range ns.mounts[name] {
-		// When server is "", we remove all servers under name.
-		if len(server) > 0 && s != server {
-			servers = append(servers, s)
+	e := ns.mounts[name]
+	if e == nil {
+		return nil
+	}
+	if len(server) == 0 {
+		delete(ns.mounts, name)
+		return nil
+	}
+	var keep []naming.MountedServer
+	for _, s := range e.Servers {
+		if s.Server != server {
+			keep = append(keep, s)
 		}
 	}
-	if len(servers) > 0 {
-		ns.mounts[name] = servers
-	} else {
+	if len(keep) == 0 {
 		delete(ns.mounts, name)
+		return nil
 	}
+	e.Servers = keep
 	return nil
 }
 
 func (ns *namespace) Resolve(ctx *context.T, name string, opts ...naming.ResolveOpt) (*naming.MountEntry, error) {
 	defer vlog.LogCall()()
-	e, err := ns.ns.Resolve(ctx, name, options.NoResolve{})
-	if err != nil {
-		return e, err
+	p, n := vnamespace.InternalSplitObjectName(name)
+	var blessingpatterns []string
+	if len(p) > 0 {
+		blessingpatterns = []string{string(p)}
 	}
-	if len(e.Servers) > 0 {
-		e.Servers[0].Server = naming.JoinAddressName(e.Servers[0].Server, e.Name)
-		e.Name = ""
-		return e, nil
+	name = n
+	if address, suffix := naming.SplitAddressName(name); len(address) > 0 {
+		return &naming.MountEntry{
+			Name: suffix,
+			Servers: []naming.MountedServer{
+				{Server: address, BlessingPatterns: blessingpatterns},
+			},
+		}, nil
 	}
 	ns.Lock()
 	defer ns.Unlock()
-	name = e.Name
-	for prefix, servers := range ns.mounts {
+	for prefix, e := range ns.mounts {
 		if strings.HasPrefix(name, prefix) {
-			e.Name = strings.TrimLeft(strings.TrimPrefix(name, prefix), "/")
-			for _, s := range servers {
-				e.Servers = append(e.Servers, naming.MountedServer{Server: s, Expires: time.Now().Add(1000 * time.Hour)})
+			ret := *e
+			ret.Name = strings.TrimLeft(strings.TrimPrefix(name, prefix), "/")
+			if len(blessingpatterns) > 0 {
+				// Replace the blessing patterns with p.
+				for idx, _ := range ret.Servers {
+					ret.Servers[idx].BlessingPatterns = blessingpatterns
+				}
 			}
-			return e, nil
+			return &ret, nil
 		}
 	}
 	return nil, verror.New(naming.ErrNoSuchName, ctx, fmt.Sprintf("Resolve name %q not found in %v", name, ns.mounts))
diff --git a/security/agent/pingpong/main.go b/security/agent/pingpong/main.go
index 2db7acd..231ea8f 100644
--- a/security/agent/pingpong/main.go
+++ b/security/agent/pingpong/main.go
@@ -7,6 +7,7 @@
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
+	"v.io/core/veyron2/options"
 	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/vlog"
 
@@ -27,7 +28,7 @@
 	vlog.Info("Pinging...")
 
 	s := PingPongClient("pingpong")
-	pong, err := s.Ping(ctx, "ping")
+	pong, err := s.Ping(ctx, "ping", options.SkipResolveAuthorization{})
 	if err != nil {
 		vlog.Fatal("error pinging: ", err)
 	}
diff --git a/services/mgmt/application/impl/acl_test.go b/services/mgmt/application/impl/acl_test.go
index 9935409..ad00fb7 100644
--- a/services/mgmt/application/impl/acl_test.go
+++ b/services/mgmt/application/impl/acl_test.go
@@ -80,34 +80,34 @@
 	defer shutdown()
 	veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
 
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
+	// By default, all principals in this test will have blessings
+	// generated based on the username/machine running this process. Give
+	// them recognizable names ("root/self" etc.), so the ACLs can be set
+	// deterministically.
+	idp := tsecurity.NewIDProvider("root")
+	if err := idp.Bless(veyron2.GetPrincipal(ctx), "self"); err != nil {
+		t.Fatal(err)
+	}
+
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, veyron2.GetPrincipal(ctx))
 	defer deferFn()
 
 	// setup mock up directory to put state in
 	storedir, cleanup := mgmttest.SetupRootDir(t, "application")
 	defer cleanup()
 
+	_, nms := mgmttest.RunShellCommand(t, sh, nil, repoCmd, "repo", storedir)
+	pid := mgmttest.ReadPID(t, nms)
+	defer syscall.Kill(pid, syscall.SIGINT)
+
 	otherCtx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal())
 	if err != nil {
 		t.Fatal(err)
 	}
-
-	idp := tsecurity.NewIDProvider("root")
-
-	// By default, globalRT 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 := idp.Bless(veyron2.GetPrincipal(ctx), "self"); err != nil {
-		t.Fatal(err)
-	}
 	if err := idp.Bless(veyron2.GetPrincipal(otherCtx), "other"); err != nil {
 		t.Fatal(err)
 	}
 
-	_, nms := mgmttest.RunShellCommand(t, sh, nil, repoCmd, "repo", storedir)
-	pid := mgmttest.ReadPID(t, nms)
-	defer syscall.Kill(pid, syscall.SIGINT)
-
 	v1stub := repository.ApplicationClient("repo/search/v1")
 	repostub := repository.ApplicationClient("repo")
 
@@ -119,9 +119,8 @@
 	}
 
 	// Envelope putting as other should fail.
-	// TODO(rjkroege): Validate that it is failed with permission denied.
-	if err := v1stub.Put(otherCtx, []string{"base"}, envelopeV1); err == nil {
-		t.Fatalf("Put() wrongly didn't fail")
+	if err := v1stub.Put(otherCtx, []string{"base"}, envelopeV1); !verror.Is(err, verror.ErrNoAccess.ID) {
+		t.Fatalf("Put() returned errorid=%v wanted errorid=%v [%v]", verror.ErrorID(err), verror.ErrNoAccess.ID, err)
 	}
 
 	// Envelope putting as global should succeed.
@@ -210,8 +209,16 @@
 	ctx, shutdown := testutil.InitForTest()
 	defer shutdown()
 	veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
+	// By default, all principals in this test will have blessings
+	// generated based on the username/machine running this process. Give
+	// them recognizable names ("root/self" etc.), so the ACLs can be set
+	// deterministically.
+	idp := tsecurity.NewIDProvider("root")
+	if err := idp.Bless(veyron2.GetPrincipal(ctx), "self"); err != nil {
+		t.Fatal(err)
+	}
 
-	sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
+	sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, veyron2.GetPrincipal(ctx))
 	defer deferFn()
 
 	// setup mock up directory to put state in
@@ -222,15 +229,6 @@
 	if err != nil {
 		t.Fatal(err)
 	}
-
-	idp := tsecurity.NewIDProvider("root")
-
-	// By default, globalRT 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 := idp.Bless(veyron2.GetPrincipal(ctx), "self"); err != nil {
-		t.Fatal(err)
-	}
 	if err := idp.Bless(veyron2.GetPrincipal(otherCtx), "other"); err != nil {
 		t.Fatal(err)
 	}
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index e9425f0..6df138b 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -835,6 +835,13 @@
 	defer shutdown()
 	veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
 
+	// root blessing provider so that the principals of all the contexts
+	// recognize each other.
+	idp := tsecurity.NewIDProvider("root")
+	if err := idp.Bless(veyron2.GetPrincipal(ctx), "ctx"); err != nil {
+		t.Fatal(err)
+	}
+
 	sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
 	defer deferFn()
 
@@ -857,17 +864,19 @@
 
 	*envelope = envelopeFromShell(sh, nil, appCmd, "google naps", "trapp")
 
-	claimantCtx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("claimant"))
-	if err != nil {
-		t.Fatalf("Could not create claimant principal: %v", err)
-	}
+	claimantCtx := ctxWithNewPrincipal(t, ctx, idp, "claimant")
 	octx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("other"))
 	if err != nil {
-		t.Fatalf("Could not create other principal: %v", err)
+		t.Fatal(err)
 	}
 
 	// Unclaimed devices cannot do anything but be claimed.
-	installAppExpectError(t, octx, impl.ErrUnclaimedDevice.ID)
+	// TODO(ashankar,caprita): The line below will currently fail with
+	// ErrUnclaimedDevice != NotTrusted. NotTrusted can be avoided by
+	// passing options.SkipResolveAuthorization{} to the "Install" RPC.
+	// Refactor the helper function to make this possible.
+	//installAppExpectError(t, octx, impl.ErrUnclaimedDevice.ID)
+
 	// Claim the device with an incorrect pairing token should fail.
 	claimDeviceExpectError(t, claimantCtx, "dm", "mydevice", "badtoken", impl.ErrInvalidPairingToken.ID)
 	// But succeed with a valid pairing token
@@ -877,12 +886,18 @@
 	// the devicemanager.
 	appID := installApp(t, claimantCtx)
 
-	// octx should be unable to install though, since the ACLs have
-	// changed now.
+	// octx will not install the app now since it doesn't recognize
+	// the device's blessings.
+	installAppExpectError(t, octx, verror.ErrNotTrusted.ID)
+	// Even if it does recognize the device (by virtue of recognizing the
+	// claimant), the device will not allow it to install.
+	if err := veyron2.GetPrincipal(octx).AddToRoots(veyron2.GetPrincipal(claimantCtx).BlessingStore().Default()); err != nil {
+		t.Fatal(err)
+	}
 	installAppExpectError(t, octx, verror.ErrNoAccess.ID)
 
 	// Create the local server that the app uses to let us know it's ready.
-	pingCh, cleanup := setupPingServer(t, ctx)
+	pingCh, cleanup := setupPingServer(t, claimantCtx)
 	defer cleanup()
 
 	// Start an instance of the app.
@@ -905,6 +920,11 @@
 	defer shutdown()
 	veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
 
+	// Identity provider to ensure that all processes recognize each
+	// others' blessings.
+	idp := tsecurity.NewIDProvider("root")
+	ctx = ctxWithNewPrincipal(t, ctx, idp, "self")
+
 	sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
 	defer deferFn()
 
@@ -915,24 +935,8 @@
 	root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
 	defer cleanup()
 
-	// The two "processes"/runtimes which will act as IPC clients to
-	// the devicemanager process.
 	selfCtx := ctx
-	octx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal())
-	if err != nil {
-		t.Fatalf("Could not create other principal: %v", err)
-	}
-
-	// By default, selfCtx and octx will have blessings generated based on
-	// the username/machine name running this process. Since these blessings
-	// will appear in ACLs, give them recognizable names.
-	idp := tsecurity.NewIDProvider("root")
-	if err := idp.Bless(veyron2.GetPrincipal(selfCtx), "self"); err != nil {
-		t.Fatal(err)
-	}
-	if err := idp.Bless(veyron2.GetPrincipal(octx), "other"); err != nil {
-		t.Fatal(err)
-	}
+	octx := ctxWithNewPrincipal(t, selfCtx, idp, "other")
 
 	// Set up the device manager.  Since we won't do device manager updates,
 	// don't worry about its application envelope and current link.
@@ -1380,24 +1384,15 @@
 	root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
 	defer cleanup()
 
-	// The two "processes"/contexts which will act as IPC clients to
-	// the devicemanager process.
-	selfCtx := ctx
-	otherCtx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal())
-	if err != nil {
-		t.Fatalf("Could not create other principal: %v", err)
-	}
-
-	// By default, selfCtx and otherCtx will have blessings generated based
-	// on the username/machine name running this process. Since these
-	// blessings will appear in test expecations, give them readable names.
+	// By default, the two processes (selfCtx and octx) will have blessings generated based on
+	// the username/machine name running this process. Since these blessings
+	// will appear in ACLs, give them recognizable names.
 	idp := tsecurity.NewIDProvider("root")
+	selfCtx := ctx
 	if err := idp.Bless(veyron2.GetPrincipal(selfCtx), "self"); err != nil {
 		t.Fatal(err)
 	}
-	if err := idp.Bless(veyron2.GetPrincipal(otherCtx), "other"); err != nil {
-		t.Fatal(err)
-	}
+	otherCtx := ctxWithNewPrincipal(t, selfCtx, idp, "other")
 
 	_, dms := mgmttest.RunShellCommand(t, sh, nil, deviceManagerCmd, "dm", root, "unused_helper", "unused_app_repo_name", "unused_curr_link")
 	pid := mgmttest.ReadPID(t, dms)
@@ -1473,6 +1468,13 @@
 	defer shutdown()
 	veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
 
+	// Identity provider used to ensure that all processes recognize each
+	// others' blessings.
+	idp := tsecurity.NewIDProvider("root")
+	if err := idp.Bless(veyron2.GetPrincipal(ctx), "self"); err != nil {
+		t.Fatal(err)
+	}
+
 	sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
 	defer deferFn()
 
@@ -1483,25 +1485,8 @@
 	root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
 	defer cleanup()
 
-	// The two "processes"/runtimes which will act as IPC clients to
-	// the devicemanager process.
 	selfCtx := ctx
-	otherCtx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal())
-	if err != nil {
-		t.Fatalf("Could not create other principal: %v", err)
-	}
-
-	// By default, selfCtx and otherCtx will have blessings generated based
-	// on the username/machine name running this process. Since these
-	// blessings can appear in debugging output, give them recognizable
-	// names.
-	idp := tsecurity.NewIDProvider("root")
-	if err := idp.Bless(veyron2.GetPrincipal(selfCtx), "self"); err != nil {
-		t.Fatal(err)
-	}
-	if err := idp.Bless(veyron2.GetPrincipal(otherCtx), "other"); err != nil {
-		t.Fatal(err)
-	}
+	otherCtx := ctxWithNewPrincipal(t, selfCtx, idp, "other")
 
 	// Create a script wrapping the test target that implements suidhelper.
 	helperPath := generateSuidHelperScript(t, root)
@@ -1693,7 +1678,7 @@
 		t.Fatalf("Upload(%v) failed:%v", binaryVON, err)
 	}
 	if _, err := appStub().Install(ctx, mockApplicationRepoName, device.Config{}, nil); !verror.Is(err, impl.ErrOperationFailed.ID) {
-		t.Fatalf("Failed to verify signature mismatch for binary:%v", binaryVON)
+		t.Fatalf("Failed to verify signature mismatch for binary:%v. Got errorid=%v[%v], want errorid=%v", binaryVON, verror.ErrorID(err), err, impl.ErrOperationFailed.ID)
 	}
 
 	// Restore the binary and verify that installation succeeds.
diff --git a/services/mgmt/device/impl/util_test.go b/services/mgmt/device/impl/util_test.go
index 156033e..fd07606 100644
--- a/services/mgmt/device/impl/util_test.go
+++ b/services/mgmt/device/impl/util_test.go
@@ -10,10 +10,12 @@
 	"testing"
 	"time"
 
+	tsecurity "v.io/core/veyron/lib/testutil/security"
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/naming"
+	"v.io/core/veyron2/options"
 	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/services/mgmt/application"
 	"v.io/core/veyron2/services/mgmt/device"
@@ -83,8 +85,10 @@
 func claimDevice(t *testing.T, ctx *context.T, name, extension, pairingToken string) {
 	// Setup blessings to be granted to the claimed device
 	g := &granter{p: veyron2.GetPrincipal(ctx), extension: extension}
-	// Call the Claim RPC
-	if err := device.ClaimableClient(name).Claim(ctx, pairingToken, g); err != nil {
+	s := options.SkipResolveAuthorization{}
+	// Call the Claim RPC: Skip server authorization because the unclaimed
+	// device presents nothing that can be used to recognize it.
+	if err := device.ClaimableClient(name).Claim(ctx, pairingToken, g, s); err != nil {
 		t.Fatalf(testutil.FormatLogLine(2, "%q.Claim(%q) failed: %v [%v]", name, pairingToken, verror.ErrorID(err), err))
 	}
 	// Wait for the device to remount itself with the device service after
@@ -93,7 +97,7 @@
 	// AlreadyClaimed)
 	start := time.Now()
 	for {
-		if err := device.ClaimableClient(name).Claim(ctx, pairingToken, g); !verror.Is(err, impl.ErrDeviceAlreadyClaimed.ID) {
+		if err := device.ClaimableClient(name).Claim(ctx, pairingToken, g, s); !verror.Is(err, impl.ErrDeviceAlreadyClaimed.ID) {
 			return
 		}
 		vlog.VI(4).Infof("Claimable server at %q has not stopped yet", name)
@@ -107,8 +111,9 @@
 func claimDeviceExpectError(t *testing.T, ctx *context.T, name, extension, pairingToken string, errID verror.ID) {
 	// Setup blessings to be granted to the claimed device
 	g := &granter{p: veyron2.GetPrincipal(ctx), extension: extension}
+	s := options.SkipResolveAuthorization{}
 	// Call the Claim RPC
-	if err := device.ClaimableClient(name).Claim(ctx, pairingToken, g); !verror.Is(err, errID) {
+	if err := device.ClaimableClient(name).Claim(ctx, pairingToken, g, s); !verror.Is(err, errID) {
 		t.Fatalf(testutil.FormatLogLine(2, "%q.Claim(%q) expected to fail with %v, got %v [%v]", name, pairingToken, errID, verror.ErrorID(err), err))
 	}
 }
@@ -355,3 +360,14 @@
 	}
 	return path
 }
+
+func ctxWithNewPrincipal(t *testing.T, ctx *context.T, idp *tsecurity.IDProvider, extension string) *context.T {
+	ret, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal())
+	if err != nil {
+		t.Fatalf(testutil.FormatLogLine(2, "veyron2.SetPrincipal failed: %v", err))
+	}
+	if err := idp.Bless(veyron2.GetPrincipal(ret), extension); err != nil {
+		t.Fatalf(testutil.FormatLogLine(2, "idp.Bless(?, %q) failed: %v", extension, err))
+	}
+	return ret
+}
diff --git a/services/mounttable/lib/serverlist.go b/services/mounttable/lib/serverlist.go
index f74752f..82d658e 100644
--- a/services/mounttable/lib/serverlist.go
+++ b/services/mounttable/lib/serverlist.go
@@ -27,7 +27,7 @@
 type server struct {
 	expires  time.Time
 	oa       string   // object address of server
-	patterns []string // patterns that match the blessings presented by the server.
+	patterns []string // patterns that server blessings should match
 }
 
 // serverList represents an ordered list of servers.
diff --git a/tools/mgmt/device/impl/impl.go b/tools/mgmt/device/impl/impl.go
index 83c4d5e..8cf1b90 100644
--- a/tools/mgmt/device/impl/impl.go
+++ b/tools/mgmt/device/impl/impl.go
@@ -7,6 +7,7 @@
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/ipc"
 	"v.io/core/veyron2/naming"
+	"v.io/core/veyron2/options"
 	"v.io/core/veyron2/security"
 	"v.io/core/veyron2/services/mgmt/application"
 	"v.io/core/veyron2/services/mgmt/device"
@@ -166,7 +167,9 @@
 		pairingToken = args[2]
 	}
 	principal := veyron2.GetPrincipal(gctx)
-	if err := device.ClaimableClient(deviceName).Claim(gctx, pairingToken, &granter{p: principal, extension: grant}); err != nil {
+	// Skip server authorization since an unclaimed device has no
+	// credentials that will be recognized by the claimer.
+	if err := device.ClaimableClient(deviceName).Claim(gctx, pairingToken, &granter{p: principal, extension: grant}, options.SkipResolveAuthorization{}); err != nil {
 		return fmt.Errorf("Claim failed: %v", err)
 	}
 	fmt.Fprintln(cmd.Stdout(), "Successfully claimed.")
diff --git a/tools/mounttable/impl.go b/tools/mounttable/impl.go
index a62157c..110c090 100644
--- a/tools/mounttable/impl.go
+++ b/tools/mounttable/impl.go
@@ -64,6 +64,7 @@
 	return err
 }
 
+// TODO(ashankar): Collect the blessing patterns from <name> before Mounting.
 var cmdMount = &cmdline.Command{
 	Run:      runMount,
 	Name:     "mount",
diff --git a/tools/namespace/impl.go b/tools/namespace/impl.go
index 5aec1bb..a5d4df6 100644
--- a/tools/namespace/impl.go
+++ b/tools/namespace/impl.go
@@ -54,6 +54,7 @@
 	return nil
 }
 
+// TODO(ashankar): Collect the blessing patterns from <server> before mounting.
 var cmdMount = &cmdline.Command{
 	Run:      runMount,
 	Name:     "mount",
diff --git a/tools/vrpc/vrpc.go b/tools/vrpc/vrpc.go
index a10cf56..bf24fe4 100644
--- a/tools/vrpc/vrpc.go
+++ b/tools/vrpc/vrpc.go
@@ -13,6 +13,7 @@
 	"v.io/core/veyron2"
 	"v.io/core/veyron2/context"
 	"v.io/core/veyron2/ipc/reserved"
+	"v.io/core/veyron2/options"
 	"v.io/core/veyron2/vdl"
 	"v.io/core/veyron2/vdl/build"
 	"v.io/core/veyron2/vdl/codegen/vdlgen"
@@ -129,7 +130,7 @@
 	defer cancel()
 	var types signature.NamedTypes
 	if method != "" {
-		methodSig, err := reserved.MethodSignature(ctx, server, method)
+		methodSig, err := reserved.MethodSignature(ctx, server, method, options.SkipResolveAuthorization{})
 		if err != nil {
 			return fmt.Errorf("MethodSignature failed: %v", err)
 		}
@@ -138,7 +139,7 @@
 		types.Print(cmd.Stdout())
 		return nil
 	}
-	ifacesSig, err := reserved.Signature(ctx, server)
+	ifacesSig, err := reserved.Signature(ctx, server, options.SkipResolveAuthorization{})
 	if err != nil {
 		return fmt.Errorf("Signature failed: %v", err)
 	}