veyron2/ipc: Support for granting credentials to servers in the form of blessings.
This change makes it possible for a client to provide additional credentials,
bound to the identity of the server, in the form of a blessed identity to
a server when making the request.
The server can access this credential via ipc.Context.Blessing.
Change-Id: I67dde80b7038b0ebb9b27f4917ae218b62ec13f0
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index 4b53246..89af1cd 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -63,6 +63,10 @@
return fmt.Sprintf("%v", call.LocalID()), fmt.Sprintf("%v", call.RemoteID())
}
+func (*testServer) EchoBlessing(call ipc.ServerCall, arg string) (result, blessing string) {
+ return arg, fmt.Sprintf("%v", call.Blessing())
+}
+
func (*testServer) EchoAndError(call ipc.ServerCall, arg string) (string, error) {
result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", call.Method(), call.Suffix(), arg)
if arg == "error" {
@@ -278,16 +282,20 @@
return
}
+func bless(blessor security.PrivateID, blessee security.PublicID, name string, caveats ...security.ServiceCaveat) security.PublicID {
+ blessed, err := blessor.Bless(blessee, name, 24*time.Hour, caveats)
+ if err != nil {
+ panic(err)
+ }
+ return blessed
+}
+
func derive(blessor security.PrivateID, name string, caveats ...security.ServiceCaveat) security.PrivateID {
id, err := isecurity.NewPrivateID("irrelevant")
if err != nil {
panic(err)
}
- blessedID, err := blessor.Bless(id.PublicID(), name, 5*time.Minute, caveats)
- if err != nil {
- panic(err)
- }
- derivedID, err := id.Derive(blessedID)
+ derivedID, err := id.Derive(bless(blessor, id.PublicID(), name, caveats...))
if err != nil {
panic(err)
}
@@ -302,8 +310,8 @@
}
func TestStartCall(t *testing.T) {
- authorizeErr := "has one or more invalid caveats"
- nameErr := "does not have a name matching the provided pattern"
+ authorizeErr := "not authorized because"
+ nameErr := "does not match the provided pattern"
cavOnlyV1 := security.UniversalCaveat(caveat.PeerIdentity{"client/v1"})
now := time.Now()
@@ -435,6 +443,49 @@
}
}
+// granter implements ipc.Granter, returning a fixed (security.PublicID, error) pair.
+type granter struct {
+ ipc.CallOpt
+ id security.PublicID
+ err error
+}
+
+func (g granter) Grant(id security.PublicID) (security.PublicID, error) { return g.id, g.err }
+
+func TestBlessing(t *testing.T) {
+ b := createBundle(t, clientID, serverID, &testServer{})
+ defer b.cleanup(t)
+
+ tests := []struct {
+ granter ipc.CallOpt
+ blessing, starterr, finisherr string
+ }{
+ {blessing: "<nil>"},
+ {granter: granter{id: bless(clientID, serverID.PublicID(), "blessed")}, blessing: "client/blessed"},
+ {granter: granter{err: errors.New("hell no")}, starterr: "hell no"},
+ {granter: granter{id: clientID.PublicID()}, finisherr: "blessing provided not bound to this server"},
+ }
+ for _, test := range tests {
+ call, err := b.client.StartCall(&fakeContext{}, "mountpoint/server/suffix", "EchoBlessing", []interface{}{"argument"}, test.granter)
+ if !matchesErrorPattern(err, test.starterr) {
+ t.Errorf("%+v: StartCall returned error %v", test, err)
+ }
+ if err != nil {
+ continue
+ }
+ var result, blessing string
+ if err = call.Finish(&result, &blessing); !matchesErrorPattern(err, test.finisherr) {
+ t.Errorf("%+v: Finish returned error %v", test, err)
+ }
+ if err != nil {
+ continue
+ }
+ if result != "argument" || blessing != test.blessing {
+ t.Errorf("%+v: Got (%q, %q)", test, result, blessing)
+ }
+ }
+}
+
func TestRPCAuthorization(t *testing.T) {
cavOnlyEcho := security.ServiceCaveat{
Service: security.AllPrincipals,