services/role/roled/internal: Add Peer Caveats
Add an option to set peer caveats on blessings issued by the role
server.
Change-Id: Ic7fc583f5a096b27a00139a6e7d12ea608a70eb1
diff --git a/services/role/roled/internal/config.vdl b/services/role/roled/internal/config.vdl
index 734ca95..e940903 100644
--- a/services/role/roled/internal/config.vdl
+++ b/services/role/roled/internal/config.vdl
@@ -28,4 +28,8 @@
// string representation of a time.Duration, e.g. "24h". An empty string
// indicates that the role blessing will not expire.
Expiry string
+ // The blessings issued for this role will only be valid for
+ // communicating with peers that match at least one of these patterns.
+ // If the list is empty, all peers are allowed.
+ Peers []security.BlessingPattern
}
diff --git a/services/role/roled/internal/config.vdl.go b/services/role/roled/internal/config.vdl.go
index 0928eb7..7e23661 100644
--- a/services/role/roled/internal/config.vdl.go
+++ b/services/role/roled/internal/config.vdl.go
@@ -37,6 +37,10 @@
// string representation of a time.Duration, e.g. "24h". An empty string
// indicates that the role blessing will not expire.
Expiry string
+ // The blessings issued for this role will only be valid for
+ // communicating with peers that match at least one of these patterns.
+ // If the list is empty, all peers are allowed.
+ Peers []security.BlessingPattern
}
func (Config) __VDLReflect(struct {
diff --git a/services/role/roled/internal/role.go b/services/role/roled/internal/role.go
index ee578d4..ad1ea41 100644
--- a/services/role/roled/internal/role.go
+++ b/services/role/roled/internal/role.go
@@ -85,18 +85,26 @@
}
func caveats(ctx *context.T, config *Config) ([]security.Caveat, error) {
- if config.Expiry == "" {
- return nil, nil
+ var caveats []security.Caveat
+ if config.Expiry != "" {
+ d, err := time.ParseDuration(config.Expiry)
+ if err != nil {
+ return nil, verror.Convert(verror.ErrInternal, ctx, err)
+ }
+ expiry, err := security.ExpiryCaveat(time.Now().Add(d))
+ if err != nil {
+ return nil, verror.Convert(verror.ErrInternal, ctx, err)
+ }
+ caveats = append(caveats, expiry)
}
- d, err := time.ParseDuration(config.Expiry)
- if err != nil {
- return nil, verror.Convert(verror.ErrInternal, ctx, err)
+ if len(config.Peers) != 0 {
+ peer, err := security.NewCaveat(security.PeerBlessingsCaveat, config.Peers)
+ if err != nil {
+ return nil, verror.Convert(verror.ErrInternal, ctx, err)
+ }
+ caveats = append(caveats, peer)
}
- expiry, err := security.ExpiryCaveat(time.Now().Add(d))
- if err != nil {
- return nil, verror.Convert(verror.ErrInternal, ctx, err)
- }
- return []security.Caveat{expiry}, nil
+ return caveats, nil
}
func createBlessings(ctx *context.T, config *Config, principal security.Principal, extensions []string, caveats []security.Caveat, dischargerLocation string) (security.Blessings, error) {
diff --git a/services/role/roled/internal/role_test.go b/services/role/roled/internal/role_test.go
index 483279f..30d927d 100644
--- a/services/role/roled/internal/role_test.go
+++ b/services/role/roled/internal/role_test.go
@@ -109,16 +109,91 @@
if verror.ErrorID(err) != tc.errID {
t.Errorf("unexpected error ID for (%q, %q). Got %#v, expected %#v", user, tc.role, verror.ErrorID(err), tc.errID)
}
- if err == nil {
- previousBlessings, _ := v23.GetPrincipal(tc.ctx).BlessingStore().Set(blessings, security.AllPrincipals)
- blessingNames, rejected := callTest(t, tc.ctx, testAddr)
- if !reflect.DeepEqual(blessingNames, tc.blessings) {
- t.Errorf("unexpected blessings for (%q, %q). Got %q, expected %q", user, tc.role, blessingNames, tc.blessings)
- }
- if len(rejected) != 0 {
- t.Errorf("unexpected rejected blessings for (%q, %q): %q", user, tc.role, rejected)
- }
- v23.GetPrincipal(tc.ctx).BlessingStore().Set(previousBlessings, security.AllPrincipals)
+ if err != nil {
+ continue
+ }
+ previousBlessings, _ := v23.GetPrincipal(tc.ctx).BlessingStore().Set(blessings, security.AllPrincipals)
+ blessingNames, rejected := callTest(t, tc.ctx, testAddr)
+ if !reflect.DeepEqual(blessingNames, tc.blessings) {
+ t.Errorf("unexpected blessings for (%q, %q). Got %q, expected %q", user, tc.role, blessingNames, tc.blessings)
+ }
+ if len(rejected) != 0 {
+ t.Errorf("unexpected rejected blessings for (%q, %q): %q", user, tc.role, rejected)
+ }
+ v23.GetPrincipal(tc.ctx).BlessingStore().Set(previousBlessings, security.AllPrincipals)
+ }
+}
+
+func TestPeerBlessingCaveats(t *testing.T) {
+ ctx, shutdown := v23.Init()
+ defer shutdown()
+
+ workdir, err := ioutil.TempDir("", "test-role-server-")
+ if err != nil {
+ t.Fatal("ioutil.TempDir failed: %v", err)
+ }
+ defer os.RemoveAll(workdir)
+
+ roleConf := irole.Config{
+ Members: []security.BlessingPattern{"root/users/user/_role"},
+ Peers: []security.BlessingPattern{
+ security.BlessingPattern("root/peer1"),
+ security.BlessingPattern("root/peer3"),
+ },
+ }
+ irole.WriteConfig(t, roleConf, filepath.Join(workdir, "role.conf"))
+
+ var (
+ root = testutil.NewIDProvider("root")
+ user = newPrincipalContext(t, ctx, root, "users/user/_role")
+ peer1 = newPrincipalContext(t, ctx, root, "peer1")
+ peer2 = newPrincipalContext(t, ctx, root, "peer2")
+ peer3 = newPrincipalContext(t, ctx, root, "peer3")
+ )
+
+ roleAddr := newRoleServer(t, newPrincipalContext(t, ctx, root, "roles"), workdir)
+
+ tDisp := &testDispatcher{}
+ server1, testPeer1 := newServer(t, peer1)
+ if err := server1.ServeDispatcher("", tDisp); err != nil {
+ t.Fatalf("server.ServeDispatcher failed: %v", err)
+ }
+ server2, testPeer2 := newServer(t, peer2)
+ if err := server2.ServeDispatcher("", tDisp); err != nil {
+ t.Fatalf("server.ServeDispatcher failed: %v", err)
+ }
+ server3, testPeer3 := newServer(t, peer3)
+ if err := server3.ServeDispatcher("", tDisp); err != nil {
+ t.Fatalf("server.ServeDispatcher failed: %v", err)
+ }
+
+ c := role.RoleClient(naming.Join(roleAddr, "role"))
+ blessings, err := c.SeekBlessings(user)
+ if err != nil {
+ t.Errorf("unexpected erro:", err)
+ }
+ v23.GetPrincipal(user).BlessingStore().Set(blessings, security.AllPrincipals)
+
+ testcases := []struct {
+ peer string
+ blessingNames []string
+ rejectedNames []string
+ }{
+ {testPeer1, []string{"root/roles/role"}, nil},
+ {testPeer2, nil, []string{"root/roles/role"}},
+ {testPeer3, []string{"root/roles/role"}, nil},
+ }
+ for i, tc := range testcases {
+ blessingNames, rejected := callTest(t, user, tc.peer)
+ var rejectedNames []string
+ for _, r := range rejected {
+ rejectedNames = append(rejectedNames, r.Blessing)
+ }
+ if !reflect.DeepEqual(blessingNames, tc.blessingNames) {
+ t.Errorf("Unexpected blessing names for #%d. Got %q, expected %q", i, blessingNames, tc.blessingNames)
+ }
+ if !reflect.DeepEqual(rejectedNames, tc.rejectedNames) {
+ t.Errorf("Unexpected rejected names for #%d. Got %q, expected %q", i, rejectedNames, tc.rejectedNames)
}
}
}