TBR: tools/{namespace,mounttable}: Sundry tweaks

(1) Include blessing patterns of the server when mounting.
    This helps provides clients the guarantee that the endpoint
    they communicate with is managed by a server authorized to
    use the particular object name in the mounttable.

    The tools obtain the set of authorized servers (blessing patterns)
    by extracting the blessings from the servers they are trying to
    mount.

(2) Add --insecure mode to some commands that avoids the above
    guarantee.

Change-Id: I8acb5ebf9ff187bdd57db2b1789e96e173667580
diff --git a/lib/testutil/v23tests/v23tests_test.go b/lib/testutil/v23tests/v23tests_test.go
index 4c5b06c..c792e1f 100644
--- a/lib/testutil/v23tests/v23tests_test.go
+++ b/lib/testutil/v23tests/v23tests_test.go
@@ -65,7 +65,7 @@
 		inv := nsBin.Start("glob", "...")
 		parts := re.FindStringSubmatch(inv.ReadLine())
 		if len(parts) == 2 {
-			if got, want := proxyAddress, parts[1]; got != want {
+			if got, want := fmt.Sprintf("[root/child]%v", proxyAddress), parts[1]; got != want {
 				t.Fatalf("got: %v, want: %v", got, want)
 			} else {
 				break
diff --git a/services/mounttable/mounttabled/mounttabled_v23_test.go b/services/mounttable/mounttabled/mounttabled_v23_test.go
index 6faaa8a..a8d71e3 100644
--- a/services/mounttable/mounttabled/mounttabled_v23_test.go
+++ b/services/mounttable/mounttabled/mounttabled_v23_test.go
@@ -30,11 +30,11 @@
 	// Get the neighborhood endpoint from the mounttable.
 	neighborhoodEndpoint := clientBin.Start("glob", name, "nh").ExpectSetEventuallyRE(`^nh (.*) \(TTL .*\)$`)[0][1]
 
-	if clientBin.Start("mount", name+"/myself", name, "5m").Wait(os.Stdout, os.Stderr) != nil {
-		i.Fatalf("failed to mount the mounttable on itself")
+	if err := clientBin.Start("mount", "--blessing_pattern=...", name+"/myself", name, "5m").Wait(os.Stdout, os.Stderr); err != nil {
+		i.Fatalf("failed to mount the mounttable on itself: %v", err)
 	}
-	if clientBin.Start("mount", name+"/google", "/www.google.com:80", "5m").Wait(os.Stdout, os.Stderr) != nil {
-		i.Fatalf("failed to mount www.google.com")
+	if err := clientBin.Start("mount", "--blessing_pattern=...", name+"/google", "/www.google.com:80", "5m").Wait(os.Stdout, os.Stderr); err != nil {
+		i.Fatalf("failed to mount www.google.com: %v", err)
 	}
 
 	// Test glob output. We expect three entries (two we mounted plus the
diff --git a/tools/mgmt/mgmt_v23_test.go b/tools/mgmt/mgmt_v23_test.go
index 1fa0fef..e9411dc 100644
--- a/tools/mgmt/mgmt_v23_test.go
+++ b/tools/mgmt/mgmt_v23_test.go
@@ -424,7 +424,11 @@
 	}
 	namespaceRoot, _ := i.GetVar("NAMESPACE_ROOT")
 	n = mtEP + "/global"
-	if got, want := run(namespaceBin, "resolve", n), namespaceRoot; got != want {
+	// TODO(ashankar): The expected blessings of the namespace root should
+	// also be from some VAR or something.  For now, hardcoded, but this
+	// should be fixed along with
+	// https://github.com/veyron/release-issues/issues/98
+	if got, want := run(namespaceBin, "resolve", n), fmt.Sprintf("[alice/myworkstation]%v", namespaceRoot); got != want {
 		i.Fatalf("got %q, want %q", got, want)
 	}
 
diff --git a/tools/mgmt/suid_test.sh b/tools/mgmt/suid_test.sh
index 09342f1..b44bfb2 100755
--- a/tools/mgmt/suid_test.sh
+++ b/tools/mgmt/suid_test.sh
@@ -299,7 +299,7 @@
   # Verify that the local mounttable exists, and that the device manager, the
   # global namespace, and the neighborhood are mounted on it.
   shell_test::assert_ne $("${NAMESPACE_BIN}" resolve "${MT_EP}/devmgr") "" "${LINENO}"
-  shell_test::assert_eq $("${NAMESPACE_BIN}" resolve "${MT_EP}/global") "${NAMESPACE_ROOT}" "${LINENO}"
+  shell_test::assert_eq $("${NAMESPACE_BIN}" resolve "${MT_EP}/global") "[alice/myworkstation]${NAMESPACE_ROOT}" "${LINENO}"
   shell_test::assert_ne $("${NAMESPACE_BIN}" resolve "${MT_EP}/nh") "" "${LINENO}"
 
   # Suspend the device manager.
diff --git a/tools/mounttable/doc.go b/tools/mounttable/doc.go
index 97f82c8..1a32f91 100644
--- a/tools/mounttable/doc.go
+++ b/tools/mounttable/doc.go
@@ -71,7 +71,7 @@
 Mounts a server <name> onto a mount table
 
 Usage:
-   mounttable mount <mount name> <name> <ttl> [M|R]
+   mounttable mount [flags] <mount name> <name> <ttl> [M|R]
 
 <mount name> is a mount name on a mount table.
 
@@ -83,6 +83,12 @@
 [M|R] are mount options. M indicates that <name> is a mounttable. R indicates
 that existing entries should be removed.
 
+The mounttable mount flags are:
+ -blessing_pattern=[]
+   blessing pattern that matches the blessings of the server being mounted. Can
+   be specified multiple times to add multiple patterns. If none is provided,
+   the server will be contacted to determine this value.
+
 Mounttable Unmount
 
 removes server <name> from the mount table
diff --git a/tools/mounttable/impl.go b/tools/mounttable/impl.go
index 5b66223..52ec3ea 100644
--- a/tools/mounttable/impl.go
+++ b/tools/mounttable/impl.go
@@ -10,6 +10,8 @@
 	"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"
 	"v.io/lib/cmdline"
 )
 
@@ -67,7 +69,23 @@
 	return nil
 }
 
-// TODO(ashankar): Collect the blessing patterns from <name> before Mounting.
+type blessingPatterns struct {
+	list []security.BlessingPattern
+}
+
+func (bp *blessingPatterns) Set(s string) error {
+	bp.list = append(bp.list, security.BlessingPattern(s))
+	return nil
+}
+
+func (bp *blessingPatterns) String() string {
+	return fmt.Sprintf("%v", bp.list)
+}
+
+func (bp *blessingPatterns) Get() interface{} { return bp.list }
+
+var flagMountBlessingPatterns blessingPatterns
+
 var cmdMount = &cmdline.Command{
 	Run:      runMount,
 	Name:     "mount",
@@ -92,6 +110,8 @@
 	if got < 2 || got > 4 {
 		return cmd.UsageErrorf("mount: incorrect number of arguments, expected 2, 3, or 4, got %d", got)
 	}
+	name := args[0]
+	server := args[1]
 	var flags naming.MountFlag
 	var seconds uint32
 	if got >= 3 {
@@ -114,7 +134,16 @@
 	ctx, cancel := context.WithTimeout(gctx, time.Minute)
 	defer cancel()
 	client := veyron2.GetClient(ctx)
-	call, err := client.StartCall(ctx, args[0], "Mount", []interface{}{args[1], seconds, flags}, options.NoResolve{})
+
+	patterns := flagMountBlessingPatterns.list
+	if len(patterns) == 0 {
+		var err error
+		if patterns, err = blessingPatternsFromServer(ctx, server); err != nil {
+			return err
+		}
+		vlog.Infof("Server at %q has blessings %v", name, patterns)
+	}
+	call, err := client.StartCall(ctx, name, "MountX", []interface{}{server, patterns, seconds, flags}, options.NoResolve{})
 	if err != nil {
 		return err
 	}
@@ -186,6 +215,7 @@
 }
 
 func root() *cmdline.Command {
+	cmdMount.Flags.Var(&flagMountBlessingPatterns, "blessing_pattern", "blessing pattern that matches the blessings of the server being mounted. Can be specified multiple times to add multiple patterns. If none is provided, the server will be contacted to determine this value.")
 	return &cmdline.Command{
 		Name:  "mounttable",
 		Short: "Tool for interacting with a Veyron mount table",
@@ -195,3 +225,25 @@
 		Children: []*cmdline.Command{cmdGlob, cmdMount, cmdUnmount, cmdResolveStep},
 	}
 }
+
+func blessingPatternsFromServer(ctx *context.T, server string) ([]security.BlessingPattern, error) {
+	vlog.Infof("Contacting %q to determine the blessings presented by it", server)
+	ctx, cancel := context.WithTimeout(ctx, time.Minute)
+	defer cancel()
+	call, err := veyron2.GetClient(ctx).StartCall(ctx, server, ipc.ReservedSignature, nil)
+	if err != nil {
+		return nil, fmt.Errorf("Unable to extract blessings presented by %q: %v", server, err)
+	}
+	blessings, _ := call.RemoteBlessings()
+	if len(blessings) == 0 {
+		return nil, fmt.Errorf("No recognizable blessings presented by %q, it cannot be securely mounted", server)
+	}
+	// This translation between BlessingPattern and string is silly!
+	// Kill the BlessingPatterns type and make methods on that type
+	// functions instead!
+	patterns := make([]security.BlessingPattern, len(blessings))
+	for i := range blessings {
+		patterns[i] = security.BlessingPattern(blessings[i])
+	}
+	return patterns, nil
+}
diff --git a/tools/mounttable/impl_test.go b/tools/mounttable/impl_test.go
index d4109d7..9976a36 100644
--- a/tools/mounttable/impl_test.go
+++ b/tools/mounttable/impl_test.go
@@ -131,7 +131,7 @@
 	stdout.Reset()
 
 	// Test the 'mount' command.
-	if err := cmd.Execute([]string{"mount", naming.JoinAddressName(endpoint.String(), ""), "server", "123s"}); err != nil {
+	if err := cmd.Execute([]string{"mount", "server", naming.JoinAddressName(endpoint.String(), ""), "123s"}); err != nil {
 		t.Fatalf("%v", err)
 	}
 	if expected, got := "Name mounted successfully.", strings.TrimSpace(stdout.String()); got != expected {
@@ -140,7 +140,7 @@
 	stdout.Reset()
 
 	// Test the 'unmount' command.
-	if err := cmd.Execute([]string{"unmount", naming.JoinAddressName(endpoint.String(), ""), "server"}); err != nil {
+	if err := cmd.Execute([]string{"unmount", "server", naming.JoinAddressName(endpoint.String(), "")}); err != nil {
 		t.Fatalf("%v", err)
 	}
 	if expected, got := "Unmount successful or name not mounted.", strings.TrimSpace(stdout.String()); got != expected {
diff --git a/tools/namespace/doc.go b/tools/namespace/doc.go
index 44bcaf5..d91e249 100644
--- a/tools/namespace/doc.go
+++ b/tools/namespace/doc.go
@@ -76,13 +76,19 @@
 Adds server <server> to the namespace with name <name>.
 
 Usage:
-   namespace mount <name> <server> <ttl>
+   namespace mount [flags] <name> <server> <ttl>
 
 <name> is the name to add to the namespace. <server> is the object address of
 the server to add. <ttl> is the TTL of the new entry. It is a decimal number
 followed by a unit suffix (s, m, h). A value of 0s represents an infinite
 duration.
 
+The namespace mount flags are:
+ -blessing_pattern=[]
+   Blessing pattern that is matched by the blessings of the server being
+   mounted. If none is provided, the server will be contacted to determine this
+   value.
+
 Namespace Unmount
 
 Removes server <server> with name <name> from the namespace.
@@ -98,19 +104,29 @@
 Translates a object name to its object address(es).
 
 Usage:
-   namespace resolve <name>
+   namespace resolve [flags] <name>
 
 <name> is the name to resolve.
 
+The namespace resolve flags are:
+ -insecure=false
+   Insecure mode: May return results from untrusted servers and invoke Resolve
+   on untrusted mounttables
+
 Namespace Resolvetomt
 
 Finds the address of the mounttable that holds an object name.
 
 Usage:
-   namespace resolvetomt <name>
+   namespace resolvetomt [flags] <name>
 
 <name> is the name to resolve.
 
+The namespace resolvetomt flags are:
+ -insecure=false
+   Insecure mode: May return results from untrusted servers and invoke Resolve
+   on untrusted mounttables
+
 Namespace Help
 
 Help with no args displays the usage of the parent command.
diff --git a/tools/namespace/impl.go b/tools/namespace/impl.go
index a5d4df6..630ab18 100644
--- a/tools/namespace/impl.go
+++ b/tools/namespace/impl.go
@@ -6,11 +6,19 @@
 
 	"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/vlog"
 	"v.io/lib/cmdline"
 )
 
+var (
+	flagInsecureResolve     bool
+	flagInsecureResolveToMT bool
+	flagMountBlessings      listFlag
+)
+
 var cmdGlob = &cmdline.Command{
 	Run:      runGlob,
 	Name:     "glob",
@@ -44,7 +52,7 @@
 		case *naming.MountEntry:
 			fmt.Fprint(cmd.Stdout(), v.Name)
 			for _, s := range v.Servers {
-				fmt.Fprintf(cmd.Stdout(), " %s (Expires %s)", s.Server, s.Expires)
+				fmt.Fprintf(cmd.Stdout(), " %v%s (Expires %s)", fmtBlessingPatterns(s.BlessingPatterns), s.Server, s.Expires)
 			}
 			fmt.Fprintln(cmd.Stdout())
 		case *naming.GlobError:
@@ -54,7 +62,6 @@
 	return nil
 }
 
-// TODO(ashankar): Collect the blessing patterns from <server> before mounting.
 var cmdMount = &cmdline.Command{
 	Run:      runMount,
 	Name:     "mount",
@@ -85,10 +92,18 @@
 	ctx, cancel := context.WithTimeout(gctx, time.Minute)
 	defer cancel()
 
+	blessings := flagMountBlessings.list
+	if len(blessings) == 0 {
+		// Obtain the blessings of the running server so it can be mounted with
+		// those blessings.
+		if blessings, err = blessingsOfRunningServer(ctx, server); err != nil {
+			return err
+		}
+		vlog.Infof("Server at %q has blessings %v", server, blessings)
+	}
 	ns := veyron2.GetNamespace(ctx)
-
-	if err = ns.Mount(ctx, name, server, ttl); err != nil {
-		vlog.Infof("ns.Mount(%q, %q, %s) failed: %v", name, server, ttl, err)
+	if err = ns.Mount(ctx, name, server, ttl, naming.MountedServerBlessingsOpt(blessings)); err != nil {
+		vlog.Infof("ns.Mount(%q, %q, %s, %v) failed: %v", name, server, ttl, blessings, err)
 		return err
 	}
 	fmt.Fprintln(cmd.Stdout(), "Server mounted successfully.")
@@ -147,13 +162,17 @@
 
 	ns := veyron2.GetNamespace(ctx)
 
-	me, err := ns.Resolve(ctx, name)
+	var opts []naming.ResolveOpt
+	if flagInsecureResolve {
+		opts = append(opts, options.SkipResolveAuthorization{})
+	}
+	me, err := ns.Resolve(ctx, name, opts...)
 	if err != nil {
 		vlog.Infof("ns.Resolve(%q) failed: %v", name, err)
 		return err
 	}
-	for _, s := range me.Names() {
-		fmt.Fprintln(cmd.Stdout(), s)
+	for i := range me.Servers {
+		fmt.Fprintln(cmd.Stdout(), fmtServer(me, i))
 	}
 	return nil
 }
@@ -177,19 +196,25 @@
 	defer cancel()
 
 	ns := veyron2.GetNamespace(ctx)
-
-	e, err := ns.ResolveToMountTable(ctx, name)
+	var opts []naming.ResolveOpt
+	if flagInsecureResolveToMT {
+		opts = append(opts, options.SkipResolveAuthorization{})
+	}
+	e, err := ns.ResolveToMountTable(ctx, name, opts...)
 	if err != nil {
 		vlog.Infof("ns.ResolveToMountTable(%q) failed: %v", name, err)
 		return err
 	}
-	for _, s := range e.Servers {
-		fmt.Fprintln(cmd.Stdout(), naming.JoinAddressName(s.Server, e.Name))
+	for i := range e.Servers {
+		fmt.Fprintln(cmd.Stdout(), fmtServer(e, i))
 	}
 	return nil
 }
 
 func root() *cmdline.Command {
+	cmdResolve.Flags.BoolVar(&flagInsecureResolve, "insecure", false, "Insecure mode: May return results from untrusted servers and invoke Resolve on untrusted mounttables")
+	cmdResolveToMT.Flags.BoolVar(&flagInsecureResolveToMT, "insecure", false, "Insecure mode: May return results from untrusted servers and invoke Resolve on untrusted mounttables")
+	cmdMount.Flags.Var(&flagMountBlessings, "blessing_pattern", "Blessing pattern that is matched by the blessings of the server being mounted. If none is provided, the server will be contacted to determine this value.")
 	return &cmdline.Command{
 		Name:  "namespace",
 		Short: "Tool for interacting with the Veyron namespace",
@@ -203,3 +228,43 @@
 		Children: []*cmdline.Command{cmdGlob, cmdMount, cmdUnmount, cmdResolve, cmdResolveToMT},
 	}
 }
+
+func fmtServer(m *naming.MountEntry, idx int) string {
+	s := m.Servers[idx]
+	return fmt.Sprintf("%v%s", fmtBlessingPatterns(s.BlessingPatterns), naming.JoinAddressName(s.Server, m.Name))
+}
+
+func fmtBlessingPatterns(p []string) string {
+	if len(p) == 0 {
+		return ""
+	}
+	return fmt.Sprintf("%v", p)
+}
+
+func blessingsOfRunningServer(ctx *context.T, server string) ([]string, error) {
+	vlog.Infof("Contacting %q to determine the blessings presented by it", server)
+	ctx, cancel := context.WithTimeout(ctx, time.Minute)
+	defer cancel()
+	call, err := veyron2.GetClient(ctx).StartCall(ctx, server, ipc.ReservedSignature, nil)
+	if err != nil {
+		return nil, fmt.Errorf("Unable to extract blessings presented by %q: %v", server, err)
+	}
+	blessings, _ := call.RemoteBlessings()
+	if len(blessings) == 0 {
+		return nil, fmt.Errorf("No recognizable blessings presented by %q, it cannot be securely mounted", server)
+	}
+	return blessings, nil
+}
+
+type listFlag struct {
+	list []string
+}
+
+func (l *listFlag) Set(s string) error {
+	l.list = append(l.list, s)
+	return nil
+}
+
+func (l *listFlag) Get() interface{} { return l.list }
+
+func (l *listFlag) String() string { return fmt.Sprintf("%v", l.list) }