"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 {