veyron/services/wsprd: Added an JSIdentityStore that will back the
PublicID handles that are passed to Javascript as well as implemented
support for blessing identities.

Change-Id: I188597e54923cc88bb7d9c509de705fd29eb09eb
diff --git a/services/wsprd/app/app.go b/services/wsprd/app/app.go
index abe25d9..f70647d 100644
--- a/services/wsprd/app/app.go
+++ b/services/wsprd/app/app.go
@@ -8,7 +8,10 @@
 	"fmt"
 	"io"
 	"sync"
+	"time"
 
+	"veyron/security/caveat"
+	"veyron/services/wsprd/identity"
 	"veyron/services/wsprd/ipc/client"
 	"veyron/services/wsprd/ipc/server"
 	"veyron/services/wsprd/ipc/stream"
@@ -18,6 +21,7 @@
 	"veyron2/context"
 	"veyron2/ipc"
 	"veyron2/rt"
+	"veyron2/security"
 	"veyron2/verror"
 	"veyron2/vlog"
 	"veyron2/vom"
@@ -54,6 +58,26 @@
 	inType vom.Type
 }
 
+type jsonServiceCaveat struct {
+	Type    string `json:"_type"`
+	Service security.PrincipalPattern
+	Data    json.RawMessage
+}
+
+type blessingRequest struct {
+	Handle     int64
+	Caveats    []jsonServiceCaveat
+	DurationMs int64
+	Name       string
+}
+
+// PublicIDHandle is a handle given to Javascript that is linked
+// to a PublicID in go.
+type PublicIDHandle struct {
+	Handle int64
+	Names  []string
+}
+
 // Controller represents all the state of a Veyron Web App.  This is the struct
 // that is in charge performing all the veyron options.
 type Controller struct {
@@ -91,6 +115,9 @@
 	client ipc.Client
 
 	veyronProxyEP string
+
+	// Store for all the PublicIDs that javascript has a handle to.
+	idStore *identity.JSPublicIDHandles
 }
 
 // NewController creates a new Controller.  writerCreator will be used to create a new flow for rpcs to
@@ -113,6 +140,7 @@
 		client:        client,
 		writerCreator: writerCreator,
 		veyronProxyEP: veyronProxyEP,
+		idStore:       identity.NewJSPublicIDHandles(),
 	}
 	controller.setup()
 	return controller, nil
@@ -215,6 +243,14 @@
 	return c.rt
 }
 
+// AddIdentity adds the PublicID to the local id store and returns
+// the handle to it.  This function exists because JS only has
+// a handle to the PublicID to avoid shipping the blessing forest
+// to JS and back.
+func (c *Controller) AddIdentity(id security.PublicID) int64 {
+	return c.idStore.Add(id)
+}
+
 // Cleanup cleans up any outstanding rpcs.
 func (c *Controller) Cleanup() {
 	c.logger.VI(0).Info("Cleaning up websocket")
@@ -405,7 +441,6 @@
 
 // HandleStopRequest takes a request to stop a server.
 func (c *Controller) HandleStopRequest(data string, w lib.ClientWriter) {
-
 	var serverId uint64
 	decoder := json.NewDecoder(bytes.NewBufferString(data))
 	if err := decoder.Decode(&serverId); err != nil {
@@ -529,3 +564,87 @@
 		return
 	}
 }
+
+// HandleUnlinkJSIdentity removes an identity from the JS identity store.
+// data should be JSON encoded number
+func (c *Controller) HandleUnlinkJSIdentity(data string, w lib.ClientWriter) {
+	decoder := json.NewDecoder(bytes.NewBufferString(data))
+	var handle int64
+	if err := decoder.Decode(&handle); err != nil {
+		w.Error(verror.Internalf("can't unmarshal JSONMessage: %v", err))
+		return
+	}
+	c.idStore.Remove(handle)
+}
+
+// Convert the json wire format of a caveat into the right go object
+func decodeCaveat(c jsonServiceCaveat) (security.ServiceCaveat, error) {
+	var ret security.ServiceCaveat
+	ret.Service = c.Service
+	switch c.Type {
+	case "MethodCaveat":
+		ret.Caveat = &caveat.MethodRestriction{}
+	case "PeerIdentityCaveat":
+		ret.Caveat = &caveat.PeerIdentity{}
+	default:
+		return ret, verror.BadArgf("unknown caveat type %s", c.Type)
+	}
+	return ret, json.Unmarshal(c.Data, &ret.Caveat)
+}
+
+func (c *Controller) getPublicIDHandle(handle int64) (*PublicIDHandle, error) {
+	id := c.idStore.Get(handle)
+	if id == nil {
+		return nil, verror.NotFoundf("uknown public id")
+	}
+	return &PublicIDHandle{Handle: handle, Names: id.Names()}, nil
+}
+
+func (c *Controller) bless(request blessingRequest) (*PublicIDHandle, error) {
+	var caveats []security.ServiceCaveat
+	for _, c := range request.Caveats {
+		newCaveat, err := decodeCaveat(c)
+		if err != nil {
+			return nil, verror.BadArgf("failed to parse caveat: %v", err)
+		}
+		caveats = append(caveats, newCaveat)
+	}
+	duration := time.Duration(request.DurationMs) * time.Millisecond
+
+	blessee := c.idStore.Get(request.Handle)
+
+	if blessee == nil {
+		return nil, verror.NotFoundf("invalid PublicID handle")
+	}
+	blessor := c.rt.Identity()
+
+	blessed, err := blessor.Bless(blessee, request.Name, duration, caveats)
+	if err != nil {
+		return nil, err
+	}
+
+	return &PublicIDHandle{Handle: c.idStore.Add(blessed), Names: blessed.Names()}, nil
+}
+
+// HandleBlessing handles a blessing request from JS.
+func (c *Controller) HandleBlessing(data string, w lib.ClientWriter) {
+	var request blessingRequest
+	decoder := json.NewDecoder(bytes.NewBufferString(data))
+	if err := decoder.Decode(&request); err != nil {
+		w.Error(verror.Internalf("can't unmarshall message: %v", err))
+		return
+	}
+
+	handle, err := c.bless(request)
+
+	if err != nil {
+		w.Error(err)
+		return
+	}
+
+	// Send the id back.
+	if err := w.Send(lib.ResponseFinal, handle); err != nil {
+		w.Error(verror.Internalf("error marshalling results: %v", err))
+		return
+	}
+}
diff --git a/services/wsprd/app/app_test.go b/services/wsprd/app/app_test.go
index 930f79d..0368530 100644
--- a/services/wsprd/app/app_test.go
+++ b/services/wsprd/app/app_test.go
@@ -5,9 +5,11 @@
 	"encoding/json"
 	"fmt"
 	"reflect"
+	"strings"
 	"sync"
 	"testing"
 	"time"
+	"veyron/security/caveat"
 	"veyron/services/wsprd/ipc/client"
 	"veyron/services/wsprd/lib"
 	"veyron/services/wsprd/signature"
@@ -15,6 +17,7 @@
 	"veyron2/ipc"
 	"veyron2/naming"
 	"veyron2/rt"
+	"veyron2/security"
 	"veyron2/vdl/vdlutil"
 	"veyron2/verror"
 	"veyron2/vlog"
@@ -26,6 +29,12 @@
 	mounttable "veyron/services/mounttable/lib"
 )
 
+var (
+	ctxFooAlice = makeMockSecurityContext("Foo", "test/alice")
+	ctxBarAlice = makeMockSecurityContext("Bar", "test/alice")
+	ctxFooBob   = makeMockSecurityContext("Foo", "test/bob")
+	ctxBarBob   = makeMockSecurityContext("Bar", "test/bob")
+)
 var r = rt.Init()
 
 type simpleAdder struct{}
@@ -559,7 +568,8 @@
 					"Name":   "adder",
 					"Suffix": "adder",
 					"RemoteID": map[string]interface{}{
-						"Names": names,
+						"Handle": 1.0,
+						"Names":  names,
 					},
 				},
 			},
@@ -674,4 +684,258 @@
 	})
 }
 
-// TODO(bjornick): Make sure that send on stream is nonblocking
+func TestDeserializeCaveat(t *testing.T) {
+	testCases := []struct {
+		json          string
+		expectedValue security.ServiceCaveat
+	}{
+		{
+			json: `{"_type":"MethodCaveat","service":"*","data":["Get","MultiGet"]}`,
+			expectedValue: security.ServiceCaveat{
+				Service: "*",
+				Caveat:  &caveat.MethodRestriction{"Get", "MultiGet"},
+			},
+		},
+		{
+			json: `{"_type":"PeerIdentityCaveat","service":"*","data":["veyron/batman","veyron/brucewayne"]}`,
+			expectedValue: security.ServiceCaveat{
+				Service: "*",
+				Caveat:  &caveat.PeerIdentity{"veyron/batman", "veyron/brucewayne"},
+			},
+		},
+	}
+
+	for _, c := range testCases {
+		var s jsonServiceCaveat
+		if err := json.Unmarshal([]byte(c.json), &s); err != nil {
+			t.Errorf("Failed to deserialize object: %v", err)
+			return
+		}
+
+		caveat, err := decodeCaveat(s)
+		if err != nil {
+			t.Errorf("Failed to convert json caveat to go object: %v")
+			return
+		}
+
+		if !reflect.DeepEqual(caveat, c.expectedValue) {
+			t.Errorf("decoded produced the wrong value: got %v, expected %v", caveat, c.expectedValue)
+		}
+	}
+}
+
+func createChain(r veyron2.Runtime, name string) security.PrivateID {
+	id := r.Identity()
+
+	for _, component := range strings.Split(name, "/") {
+		newID, err := r.NewIdentity(component)
+		if err != nil {
+			panic(err)
+		}
+		if id == nil {
+			id = newID
+			continue
+		}
+		blessedID, err := id.Bless(newID.PublicID(), component, time.Hour, nil)
+		if err != nil {
+			panic(err)
+		}
+		id, err = newID.Derive(blessedID)
+		if err != nil {
+			panic(err)
+		}
+	}
+	return id
+}
+
+type mockSecurityContext struct {
+	method  string
+	localID security.PublicID
+}
+
+func makeMockSecurityContext(method string, name string) *mockSecurityContext {
+	return &mockSecurityContext{
+		method:  method,
+		localID: createChain(r, name).PublicID(),
+	}
+}
+
+func (m *mockSecurityContext) Method() string { return m.method }
+
+func (m *mockSecurityContext) LocalID() security.PublicID { return m.localID }
+
+func (*mockSecurityContext) Name() string { return "" }
+
+func (*mockSecurityContext) Suffix() string { return "" }
+
+func (*mockSecurityContext) Label() security.Label { return 0 }
+
+func (*mockSecurityContext) CaveatDischarges() security.CaveatDischargeMap { return nil }
+
+func (*mockSecurityContext) RemoteID() security.PublicID { return nil }
+
+func (*mockSecurityContext) LocalEndpoint() naming.Endpoint { return nil }
+
+func (*mockSecurityContext) RemoteEndpoint() naming.Endpoint { return nil }
+
+type blessingTestCase struct {
+	requestJSON             map[string]interface{}
+	expectedValidateResults map[*mockSecurityContext]bool
+	expectedErr             error
+}
+
+func runBlessingTest(c blessingTestCase, t *testing.T) {
+	controller, err := NewController(nil, "mockVeyronProxyEP")
+
+	if err != nil {
+		t.Errorf("unable to create controller: %v", err)
+		return
+	}
+	controller.AddIdentity(createChain(rt.R(), "test/bar").PublicID())
+
+	bytes, err := json.Marshal(c.requestJSON)
+
+	if err != nil {
+		t.Errorf("failed to marshal request: %v", err)
+		return
+	}
+
+	var request blessingRequest
+	if err := json.Unmarshal(bytes, &request); err != nil {
+		t.Errorf("failed to unmarshal request: %v", err)
+		return
+	}
+
+	jsId, err := controller.bless(request)
+
+	if !reflect.DeepEqual(err, c.expectedErr) {
+		t.Errorf("error response does not match: expected %v, got %v", c.expectedErr, err)
+		return
+	}
+
+	if err != nil {
+		return
+	}
+
+	id := controller.idStore.Get(jsId.Handle)
+
+	if id == nil {
+		t.Errorf("couldn't get identity from store")
+		return
+	}
+
+	for ctx, value := range c.expectedValidateResults {
+		_, err := id.Authorize(ctx)
+		if (err == nil) != value {
+			t.Errorf("authorize failed to match expected value for %v: expected %v, got %v", ctx, value, err)
+		}
+	}
+}
+
+// The names of the identity in the mock contexts are root off the runtime's
+// identity.  This function takes a name and prepends the runtime's identity's
+// name.
+func securityName(name string) string {
+	return rt.R().Identity().PublicID().Names()[0] + "/" + name
+}
+
+func TestBlessingWithNoCaveats(t *testing.T) {
+	runBlessingTest(blessingTestCase{
+		requestJSON: map[string]interface{}{
+			"handle":     1,
+			"durationMs": 10000,
+			"name":       "foo",
+		},
+		expectedValidateResults: map[*mockSecurityContext]bool{
+			ctxFooAlice: true,
+			ctxFooBob:   true,
+			ctxBarAlice: true,
+			ctxBarBob:   true,
+		},
+	}, t)
+}
+
+func TestBlessingWithMethodRestrictions(t *testing.T) {
+	runBlessingTest(blessingTestCase{
+		requestJSON: map[string]interface{}{
+			"handle":     1,
+			"durationMs": 10000,
+			"caveats": []map[string]interface{}{
+				map[string]interface{}{
+					"_type":   "MethodCaveat",
+					"service": "*",
+					"data":    []string{"Foo"},
+				},
+			},
+			"name": "foo",
+		},
+		expectedValidateResults: map[*mockSecurityContext]bool{
+			ctxFooAlice: true,
+			ctxFooBob:   true,
+			ctxBarAlice: false,
+			ctxBarBob:   false,
+		},
+	}, t)
+}
+
+func TestBlessingWithPeerRestrictions(t *testing.T) {
+	runBlessingTest(blessingTestCase{
+		requestJSON: map[string]interface{}{
+			"handle":     1,
+			"durationMs": 10000,
+			"caveats": []map[string]interface{}{
+				map[string]interface{}{
+					"_type":   "PeerIdentityCaveat",
+					"service": "*",
+					"data":    []string{securityName("test/alice")},
+				},
+			},
+			"name": "foo",
+		},
+		expectedValidateResults: map[*mockSecurityContext]bool{
+			ctxFooAlice: true,
+			ctxFooBob:   false,
+			ctxBarAlice: true,
+			ctxBarBob:   false,
+		},
+	}, t)
+}
+
+func TestBlessingWithMethodAndPeerRestrictions(t *testing.T) {
+	runBlessingTest(blessingTestCase{
+		requestJSON: map[string]interface{}{
+			"handle":     1,
+			"durationMs": 10000,
+			"caveats": []map[string]interface{}{
+				map[string]interface{}{
+					"_type":   "PeerIdentityCaveat",
+					"service": "*",
+					"data":    []string{securityName("test/alice")},
+				},
+				map[string]interface{}{
+					"_type":   "MethodCaveat",
+					"service": "*",
+					"data":    []string{"Bar"},
+				},
+			},
+			"name": "foo",
+		},
+		expectedValidateResults: map[*mockSecurityContext]bool{
+			ctxFooAlice: false,
+			ctxFooBob:   false,
+			ctxBarAlice: true,
+			ctxBarBob:   false,
+		},
+	}, t)
+}
+
+func TestBlessingWhereBlesseeDoesNotExist(t *testing.T) {
+	runBlessingTest(blessingTestCase{
+		requestJSON: map[string]interface{}{
+			"handle":     2,
+			"durationMs": 10000,
+			"name":       "foo",
+		},
+		expectedErr: verror.NotFoundf("invalid PublicID handle"),
+	}, t)
+}
diff --git a/services/wsprd/identity/js_identity_store.go b/services/wsprd/identity/js_identity_store.go
new file mode 100644
index 0000000..358228b
--- /dev/null
+++ b/services/wsprd/identity/js_identity_store.go
@@ -0,0 +1,46 @@
+package identity
+
+import "veyron2/security"
+import "sync"
+
+// JSPublicIDHandles is a store for PublicIDs in use by JS code.
+// We don't pass the full PublicID to avoid serializing and deserializing a
+// potentially huge forest of blessings.  Instead we pass to JS a handle to a public
+// identity and have all operations involve cryptographic operations call into go.
+type JSPublicIDHandles struct {
+	mu         sync.Mutex
+	lastHandle int64
+	store      map[int64]security.PublicID
+}
+
+// NewJSPublicIDHandles returns a newly initialized JSPublicIDHandles
+func NewJSPublicIDHandles() *JSPublicIDHandles {
+	return &JSPublicIDHandles{
+		store: map[int64]security.PublicID{},
+	}
+}
+
+// Add adds a PublicID to the store and returns the handle to it.
+func (s *JSPublicIDHandles) Add(identity security.PublicID) int64 {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	s.lastHandle++
+	handle := s.lastHandle
+	s.store[handle] = identity
+	return handle
+}
+
+// Remove removes the PublicID associated with the handle.
+func (s *JSPublicIDHandles) Remove(handle int64) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	delete(s.store, handle)
+}
+
+// Get returns the PublicID represented by the handle.  Returns nil
+// if no PublicID exists for the handle.
+func (s *JSPublicIDHandles) Get(handle int64) security.PublicID {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.store[handle]
+}
diff --git a/services/wsprd/ipc/server/server.go b/services/wsprd/ipc/server/server.go
index 989a053..737d085 100644
--- a/services/wsprd/ipc/server/server.go
+++ b/services/wsprd/ipc/server/server.go
@@ -34,7 +34,8 @@
 }
 
 type publicID struct {
-	Names []string
+	Handle int64
+	Names  []string
 }
 
 // call context for a serverRPCRequest
@@ -50,10 +51,20 @@
 	Err     *verror.Standard
 }
 
-type ServerHelper interface {
+type FlowHandler interface {
 	CreateNewFlow(server *Server, sender stream.Sender) *Flow
 
 	CleanupFlow(id int64)
+}
+
+type HandleStore interface {
+	// Adds an identity to the store and returns handle to the identity
+	AddIdentity(identity security.PublicID) int64
+}
+
+type ServerHelper interface {
+	FlowHandler
+	HandleStore
 
 	GetLogger() vlog.Logger
 
@@ -110,11 +121,13 @@
 		s.Lock()
 		s.outstandingServerRequests[flow.ID] = replyChan
 		s.Unlock()
+		remoteID := call.RemoteID()
 		context := serverRPCRequestContext{
 			Suffix: call.Suffix(),
 			Name:   call.Name(),
 			RemoteID: publicID{
-				Names: call.RemoteID().Names(),
+				Handle: s.helper.AddIdentity(remoteID),
+				Names:  remoteID.Names(),
 			},
 		}
 		// Send a invocation request to JavaScript
diff --git a/services/wsprd/wspr/pipe.go b/services/wsprd/wspr/pipe.go
index 14be0eb..73e5f08 100644
--- a/services/wsprd/wspr/pipe.go
+++ b/services/wsprd/wspr/pipe.go
@@ -49,6 +49,13 @@
 
 	// A request to associate an identity with an origin
 	websocketAssocIdentity = 7
+
+	// A request to bless an identity
+	websocketBlessIdentity = 8
+
+	// A request to unlink an identity.  This request means that
+	// we can remove the given handle from the handle store.
+	websocketUnlinkIdentity = 9
 )
 
 type websocketMessage struct {
@@ -260,6 +267,10 @@
 			// from javascript.
 			ctx := p.wspr.rt.NewContext()
 			go p.controller.HandleSignatureRequest(ctx, msg.Data, ww)
+		case websocketBlessIdentity:
+			go p.controller.HandleBlessing(msg.Data, ww)
+		case websocketUnlinkIdentity:
+			go p.controller.HandleUnlinkJSIdentity(msg.Data, ww)
 		default:
 			ww.Error(verror.Unknownf("unknown message type: %v", msg.Type))
 		}