"core": Make glob-patterns the default

This CL changes the semantics of patterns that do not end in "/...".
Such patterns now behave like glob patterns.
For example, "google/alice" matches
 "google"
 "google/alice"
 "google/alice/device"
 "google/alice/device/app"

In order to prevent matching extensions, the pattern must be
terminated with a "/$".
For example, "google/alice/$" only matches
 "google"
 "google/alice"
See: https://vanadium-review.googlesource.com/#/c/1757/

While explicit glob-patterns, i.e., patterns ending in "/..." are still
supported, we plan to get rid of them soon.

Change-Id: I810eaf61cc1d241ae76026dc50a7c3486f6b27dc
diff --git a/security/blessingroots_test.go b/security/blessingroots_test.go
index 49b599f..9e06948 100644
--- a/security/blessingroots_test.go
+++ b/security/blessingroots_test.go
@@ -29,7 +29,7 @@
 	}{
 		{t[0], "veyron/..."},
 		{t[1], "google/foo/..."},
-		{t[0], "google"},
+		{t[0], "google/$"},
 	}
 	for _, d := range testdata {
 		if err := br.Add(d.root, d.pattern); err != nil {
diff --git a/security/blessingstore_test.go b/security/blessingstore_test.go
index d328da4..a9b2906 100644
--- a/security/blessingstore_test.go
+++ b/security/blessingstore_test.go
@@ -22,13 +22,12 @@
 		wantErr   string
 	}{
 		{t.forAll, "...", ""},
+		{t.forAll, "$", ""},
 		{t.forFoo, "foo/...", ""},
-		{t.forBar, "bar", ""},
+		{t.forBar, "bar/$", ""},
 		{t.other, "...", "public key does not match"},
 		{t.forAll, "", "invalid BlessingPattern"},
-		{t.forAll, "foo...", "invalid BlessingPattern"},
-		{t.forAll, "...foo", "invalid BlessingPattern"},
-		{t.forAll, "foo/.../bar", "invalid BlessingPattern"},
+		{t.forAll, "foo/$/bar", "invalid BlessingPattern"},
 	}
 	added := make(map[security.BlessingPattern]security.Blessings)
 	for _, d := range testdata {
@@ -193,7 +192,7 @@
 	// Set(alice, "alice")
 	// Set(bob, "alice/...")
 	// So, {alice, bob} is shared with "alice", whilst {bob} is shared with "alice/tv"
-	if _, err := s.Set(alice, "alice"); err != nil {
+	if _, err := s.Set(alice, "alice/$"); err != nil {
 		t.Fatal(err)
 	}
 	if _, err := s.Set(bob, "alice/..."); err != nil {
@@ -208,7 +207,7 @@
 
 	// Clear out the blessing associated with "alice".
 	// Now, bob should be shared with both alice and alice/friend.
-	if _, err := s.Set(nil, "alice"); err != nil {
+	if _, err := s.Set(nil, "alice/$"); err != nil {
 		t.Fatal(err)
 	}
 	if got, want := s.ForPeer("alice"), bob; !reflect.DeepEqual(got, want) {
@@ -219,7 +218,7 @@
 	}
 
 	// Clearing out an association that doesn't exist should have no effect.
-	if _, err := s.Set(nil, "alice/enemy"); err != nil {
+	if _, err := s.Set(nil, "alice/enemy/$"); err != nil {
 		t.Fatal(err)
 	}
 	if got, want := s.ForPeer("alice"), bob; !reflect.DeepEqual(got, want) {
diff --git a/security/flag/flag_test.go b/security/flag/flag_test.go
index fbf46bc..2416001 100644
--- a/security/flag/flag_test.go
+++ b/security/flag/flag_test.go
@@ -25,10 +25,10 @@
 	acl1 = access.TaggedACLMap{}
 	acl2 = access.TaggedACLMap{
 		string(access.Read): access.ACL{
-			In: []security.BlessingPattern{"veyron/alice", "veyron/bob"},
+			In: []security.BlessingPattern{"veyron/alice/$", "veyron/bob"},
 		},
 		string(access.Write): access.ACL{
-			In: []security.BlessingPattern{"veyron/alice"},
+			In: []security.BlessingPattern{"veyron/alice/$"},
 		},
 	}
 
@@ -94,7 +94,7 @@
 		},
 		{
 			cmd:   "tamFromFlag",
-			flags: []string{"--veyron.acl.literal", `{"Read": {"In":["veyron/alice", "veyron/bob"]}, "Write": {"In":["veyron/alice"]}}`},
+			flags: []string{"--veyron.acl.literal", `{"Read": {"In":["veyron/alice/$", "veyron/bob"]}, "Write": {"In":["veyron/alice/$"]}}`},
 			auth:  "acl2",
 		},
 	}
diff --git a/services/mgmt/binary/impl/acl_test.go b/services/mgmt/binary/impl/acl_test.go
index 8962d52..6c16291 100644
--- a/services/mgmt/binary/impl/acl_test.go
+++ b/services/mgmt/binary/impl/acl_test.go
@@ -20,7 +20,6 @@
 	"v.io/core/veyron/lib/signals"
 	"v.io/core/veyron/lib/testutil"
 	tsecurity "v.io/core/veyron/lib/testutil/security"
-	vsecurity "v.io/core/veyron/security"
 	"v.io/core/veyron/services/mgmt/binary/impl"
 	mgmttest "v.io/core/veyron/services/mgmt/lib/testutil"
 )
@@ -95,27 +94,15 @@
 	defer cleanup()
 	prepDirectory(t, storedir)
 
-	otherPrincipal, err := vsecurity.NewPrincipal()
-	if err != nil {
-		t.Fatalf("NewPrincipal() failed: %v", err)
+	otherPrincipal := tsecurity.NewPrincipal("other")
+	if err := otherPrincipal.AddToRoots(selfPrincipal.BlessingStore().Default()); err != nil {
+		t.Fatalf("otherPrincipal.AddToRoots() failed: %v", err)
 	}
 	otherCtx, err := veyron2.SetPrincipal(selfCtx, otherPrincipal)
 	if err != nil {
 		t.Fatalf("SetPrincipal() failed: %v", err)
 	}
 
-	selfBlessing := selfPrincipal.BlessingStore().Default()
-	otherBlessing, err := selfPrincipal.Bless(otherPrincipal.PublicKey(), selfBlessing, "other", security.UnconstrainedUse())
-	if err != nil {
-		t.Fatalf("selfPrincipal.Bless() failed: %v", err)
-	}
-	if _, err := otherPrincipal.BlessingStore().Set(otherBlessing, "self/child"); err != nil {
-		t.Fatalf("otherPrincipal.BlessingStore() failed: %v", err)
-	}
-	if err := otherPrincipal.AddToRoots(otherBlessing); err != nil {
-		t.Fatalf("otherPrincipal.AddToRoots() failed: %v", err)
-	}
-
 	_, nms := mgmttest.RunShellCommand(t, sh, nil, binaryCmd, "bini", storedir)
 	pid := mgmttest.ReadPID(t, nms)
 	defer syscall.Kill(pid, syscall.SIGINT)
@@ -139,7 +126,11 @@
 		t.Fatalf("invokeUpload() failed %v, %v", err, streamErr)
 	}
 
-	vlog.VI(2).Infof("Verify that other can't access bini/private")
+	vlog.VI(2).Infof("Verify that in the beginning other can't access bini/private or bini/shared")
+	binary = repository.BinaryClient("bini/private")
+	if _, _, err := binary.Stat(otherCtx); !verror.Is(err, verror.NoAccess) {
+		t.Fatalf("Stat() should have failed but didn't: %v", err)
+	}
 	binary = repository.BinaryClient("bini/shared")
 	if _, _, err := binary.Stat(otherCtx); !verror.Is(err, verror.NoAccess) {
 		t.Fatalf("Stat() should have failed but didn't: %v", err)
@@ -153,36 +144,47 @@
 	}
 	expected := access.TaggedACLMap{"Admin": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}, "Read": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}, "Write": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}, "Debug": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}, "Resolve": access.ACL{In: []security.BlessingPattern{"self"}, NotIn: []string{}}}
 	if got, want := acl.Normalize(), expected.Normalize(); !reflect.DeepEqual(got, want) {
-		t.Errorf("got %#v, exected %#v ", got, want)
+		t.Errorf("got %#v, expected %#v ", got, want)
 	}
 
-	vlog.VI(2).Infof("Validate the ACL file on bini/shared.")
-	binary = repository.BinaryClient("bini/shared")
+	vlog.VI(2).Infof("Validate the ACL file on bini/private.")
+	binary = repository.BinaryClient("bini/private")
 	acl, etag, err := binary.GetACL(selfCtx)
 	if err != nil {
 		t.Fatalf("GetACL failed: %v", err)
 	}
 	if got, want := acl.Normalize(), expected.Normalize(); !reflect.DeepEqual(got, want) {
-		t.Errorf("got %#v, exected %#v ", got, want)
+		t.Errorf("got %#v, expected %#v ", got, want)
 	}
 
-	vlog.VI(2).Infof("Self modifies the ACL file on bini/shared.")
+	vlog.VI(2).Infof("self blesses other as self/other and locks the bini/private binary to itself.")
+	selfBlessing := selfPrincipal.BlessingStore().Default()
+	otherBlessing, err := selfPrincipal.Bless(otherPrincipal.PublicKey(), selfBlessing, "other", security.UnconstrainedUse())
+	if err != nil {
+		t.Fatalf("selfPrincipal.Bless() failed: %v", err)
+	}
+	if _, err := otherPrincipal.BlessingStore().Set(otherBlessing, security.AllPrincipals); err != nil {
+		t.Fatalf("otherPrincipal.BlessingStore() failed: %v", err)
+	}
+
+	vlog.VI(2).Infof("Self modifies the ACL file on bini/private.")
 	for _, tag := range access.AllTypicalTags() {
-		acl.Add("self/other", string(tag))
+		acl.Clear("self", string(tag))
+		acl.Add("self/$", string(tag))
 	}
 	if err := binary.SetACL(selfCtx, acl, etag); err != nil {
 		t.Fatalf("SetACL failed: %v", err)
 	}
 
-	vlog.VI(2).Infof(" Verify that bini/shared's acls are updated.")
-	binary = repository.BinaryClient("bini/shared")
-	updated := access.TaggedACLMap{"Admin": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}, "Read": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}, "Write": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}, "Debug": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}, "Resolve": access.ACL{In: []security.BlessingPattern{"self", "self/other"}, NotIn: []string{}}}
+	vlog.VI(2).Infof(" Verify that bini/private's acls are updated.")
+	binary = repository.BinaryClient("bini/private")
+	updated := access.TaggedACLMap{"Admin": access.ACL{In: []security.BlessingPattern{"self/$"}, NotIn: []string{}}, "Read": access.ACL{In: []security.BlessingPattern{"self/$"}, NotIn: []string{}}, "Write": access.ACL{In: []security.BlessingPattern{"self/$"}, NotIn: []string{}}, "Debug": access.ACL{In: []security.BlessingPattern{"self/$"}, NotIn: []string{}}, "Resolve": access.ACL{In: []security.BlessingPattern{"self/$"}, NotIn: []string{}}}
 	acl, _, err = binary.GetACL(selfCtx)
 	if err != nil {
 		t.Fatalf("GetACL failed: %v", err)
 	}
 	if got, want := acl.Normalize(), updated.Normalize(); !reflect.DeepEqual(got, want) {
-		t.Errorf("got %#v, exected %#v ", got, want)
+		t.Errorf("got %#v, expected %#v ", got, want)
 	}
 
 	// Other still can't access bini/shared because there's no ACL file at the
@@ -198,7 +200,7 @@
 	binary = repository.BinaryClient("bini")
 	newRootACL := make(access.TaggedACLMap)
 	for _, tag := range access.AllTypicalTags() {
-		newRootACL.Add("self", string(tag))
+		newRootACL.Add("self/$", string(tag))
 	}
 	if err := binary.SetACL(selfCtx, newRootACL, ""); err != nil {
 		t.Fatalf("SetACL failed: %v", err)
@@ -220,7 +222,7 @@
 	if err != nil {
 		t.Fatalf("GetACL() failed: %v", err)
 	}
-	acl.Add("self/other", string("Write"))
+	acl.Add("self", string("Write"))
 	err = binary.SetACL(selfCtx, acl, tag)
 	if err != nil {
 		t.Fatalf("SetACL() failed: %v", err)
@@ -256,7 +258,7 @@
 		t.Fatalf("GetACL failed: %v", err)
 	}
 	if got, want := acl.Normalize(), updated.Normalize(); !reflect.DeepEqual(want, got) {
-		t.Errorf("got %#v, exected %#v ", got, want)
+		t.Errorf("got %#v, expected %#v ", got, want)
 	}
 
 	vlog.VI(2).Infof("Other tries to exclude self by adding self to Read's notin")
diff --git a/services/mgmt/device/impl/dispatcher.go b/services/mgmt/device/impl/dispatcher.go
index 30cf651..1ad57b6 100644
--- a/services/mgmt/device/impl/dispatcher.go
+++ b/services/mgmt/device/impl/dispatcher.go
@@ -152,7 +152,9 @@
 	acl := make(access.TaggedACLMap)
 	for _, n := range names {
 		for _, tag := range access.AllTypicalTags() {
-			acl.Add(security.BlessingPattern(n), string(tag))
+			// TODO(caprita, ataly, ashankar): Do we really need the NonExtendable restriction
+			// below?
+			acl.Add(security.BlessingPattern(n).MakeNonExtendable(), string(tag))
 		}
 	}
 	if err := d.locks.SetPathACL(principal, d.getACLDir(), acl, ""); err != nil {
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index 4a6fee9..8b9a926 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -917,7 +917,7 @@
 	}
 	expectedACL := make(access.TaggedACLMap)
 	for _, tag := range access.AllTypicalTags() {
-		expectedACL[string(tag)] = access.ACL{In: []security.BlessingPattern{"root/self/mydevice"}}
+		expectedACL[string(tag)] = access.ACL{In: []security.BlessingPattern{"root/self/mydevice/$"}}
 	}
 	var b bytes.Buffer
 	if err := expectedACL.WriteTo(&b); err != nil {