Merge "veyron/services/wspr/wsprd:  Added identity store for wspr."
diff --git a/services/wspr/wsprd/lib/identity.go b/services/wspr/wsprd/lib/identity.go
new file mode 100644
index 0000000..823d4d8
--- /dev/null
+++ b/services/wspr/wsprd/lib/identity.go
@@ -0,0 +1,243 @@
+// Implements an identity manager that maps origins to veyron identities.  Each instance
+// of wspr is expected to have only one user at a time that will be signed in.  In this case,
+// the user means the person using the app.  Each user may use many different names, which in
+// practice will be done by having multiple accounts across many identity providers (i.e google,
+// facebook,etc).  This is similar to having a master identity that is linked to multiple identities
+// in today's technology. For each app/origin, the user may choose which name to provide that app,
+// which results in a blessed identity for that app.  Each blessed identity will have a different
+// private key and ideally, all accounts will share the same private key, but for now they are also
+// separate.  The identity manager only serializes the mapping of app to account and the account
+// information, but not the private keys for each app.
+// TODO(bjornick,ataly,ashankar): Have all the accounts share the same private key which will be stored
+// in a TPM, so no private key gets serialized to disk.
+
+package lib
+
+import (
+	"crypto/ecdsa"
+	"crypto/sha256"
+	"io"
+	"sync"
+	"time"
+
+	"veyron2"
+	"veyron2/security"
+	"veyron2/verror"
+	"veyron2/vom"
+)
+
+// permissions is a set of a permissions given to an app, containing the account
+// the app has access to and the caveats associated with it.
+type permissions struct {
+	// The account name that is given to an app.
+	Account string
+	Caveats []security.ServiceCaveat
+}
+
+// persistentState is the state of the manager that will be persisted to disk.
+type persistentState struct {
+	// A mapping of origins to the permissions provide for the origin (such as
+	// caveats and the account given to the origin)
+	Origins map[string]permissions
+
+	// A set of accounts that maps from a name to the account.
+	Accounts map[string]security.PrivateID
+}
+
+// Serializer is a factory for managing the readers and writers used by the IDManager
+// for serialization and deserialization
+type Serializer interface {
+	// DataWriter returns a writer that is used to write the data portion
+	// of the IDManager
+	DataWriter() io.WriteCloser
+
+	// SignatureWriter returns a writer that is used to write the signature
+	// of the serialized data.
+	SignatureWriter() io.WriteCloser
+
+	// DataReader returns a reader that is used to read the serialized data.
+	// If nil is returned, then there is no seralized data to load.
+	DataReader() io.Reader
+
+	// SignatureReader returns a reader that is used to read the signature of the
+	// serialized data.  If nil is returned, then there is no signature to load.
+	SignatureReader() io.Reader
+}
+
+var OriginDoesNotExist = verror.NotFoundf("origin not found")
+
+// IDManager manages app identities.  We only serialize the accounts associated with
+// this id manager and the mapping of apps to permissions that they were given.
+type IDManager struct {
+	mu    sync.Mutex
+	state persistentState
+
+	// The runtime that will be used to create new identities
+	rt veyron2.Runtime
+
+	serializer Serializer
+}
+
+// NewIDManager creates a new IDManager from the reader passed in. serializer can't be nil
+func NewIDManager(rt veyron2.Runtime, serializer Serializer) (*IDManager, error) {
+	result := &IDManager{
+		rt: rt,
+		state: persistentState{
+			Origins:  map[string]permissions{},
+			Accounts: map[string]security.PrivateID{},
+		},
+		serializer: serializer,
+	}
+
+	reader := serializer.DataReader()
+	var hadData bool
+	hash := sha256.New()
+	if reader != nil {
+		hadData = true
+		if err := vom.NewDecoder(io.TeeReader(reader, hash)).Decode(&result.state); err != nil {
+			return nil, err
+		}
+
+	}
+	signed := hash.Sum(nil)
+
+	var sig security.Signature
+
+	reader = serializer.SignatureReader()
+
+	var hadSig bool
+	if reader != nil {
+		hadSig = true
+		if err := vom.NewDecoder(serializer.SignatureReader()).Decode(&sig); err != nil {
+			return nil, err
+		}
+	}
+
+	if !hadSig && !hadData {
+		return result, nil
+	}
+
+	if !ecdsa.Verify(rt.Identity().PublicID().PublicKey(), signed, sig.R, sig.S) {
+		return nil, verror.NotAuthorizedf("signature verification failed")
+	}
+
+	return result, nil
+}
+
+// Save serializes the IDManager to the writer.
+func (i *IDManager) save() error {
+	hash := sha256.New()
+	writer := i.serializer.DataWriter()
+
+	if err := vom.NewEncoder(io.MultiWriter(writer, hash)).Encode(i.state); err != nil {
+		return err
+	}
+
+	if err := writer.Close(); err != nil {
+		return err
+	}
+
+	signed := hash.Sum(nil)
+	signature, err := i.rt.Identity().Sign(signed)
+
+	if err != nil {
+		return err
+	}
+
+	writer = i.serializer.SignatureWriter()
+
+	if err := vom.NewEncoder(writer).Encode(signature); err != nil {
+		return err
+	}
+
+	return writer.Close()
+}
+
+// Identity returns the identity for an origin.  Returns OriginDoesNotExist if
+// there is no identity for the origin.
+func (i *IDManager) Identity(origin string) (security.PrivateID, error) {
+	i.mu.Lock()
+	defer i.mu.Unlock()
+	perm, found := i.state.Origins[origin]
+	if !found {
+		return nil, OriginDoesNotExist
+	}
+
+	return i.generateBlessedID(origin, perm.Account, perm.Caveats)
+}
+
+// AccountsMatching returns a list of accounts that match the given pattern.
+func (i *IDManager) AccountsMatching(trustedRoot security.PrincipalPattern) []string {
+	i.mu.Lock()
+	defer i.mu.Unlock()
+	result := []string{}
+	for name, id := range i.state.Accounts {
+		if id.PublicID().Match(trustedRoot) {
+			result = append(result, name)
+		}
+	}
+	return result
+}
+
+// AddAccount associates a PrivateID with an account name.
+func (i *IDManager) AddAccount(name string, id security.PrivateID) error {
+	i.mu.Lock()
+	defer i.mu.Unlock()
+	old, existed := i.state.Accounts[name]
+	i.state.Accounts[name] = id
+	if err := i.save(); err != nil {
+		delete(i.state.Accounts, name)
+		if existed {
+			i.state.Accounts[name] = old
+		}
+		return err
+	}
+	return nil
+}
+
+// AddOrigin adds an origin to the manager linked to a the given account.
+func (i *IDManager) AddOrigin(origin string, account string, caveats []security.ServiceCaveat) error {
+	i.mu.Lock()
+	defer i.mu.Unlock()
+	if _, found := i.state.Accounts[account]; !found {
+		return verror.NotFoundf("unknown account %s", account)
+	}
+
+	old, existed := i.state.Origins[origin]
+
+	i.state.Origins[origin] = permissions{account, caveats}
+
+	if err := i.save(); err != nil {
+		delete(i.state.Origins, origin)
+		if existed {
+			i.state.Origins[origin] = old
+		}
+
+		return err
+	}
+
+	return nil
+}
+
+func (i *IDManager) generateBlessedID(name string, account string, caveats []security.ServiceCaveat) (security.PrivateID, error) {
+	blessor := i.state.Accounts[account]
+	if blessor == nil {
+		return nil, verror.NotFoundf("unknown account %s", account)
+	}
+	// The name here is irrelevant, since we'll only be storing the blessed name.
+	blessee, err := i.rt.NewIdentity(name)
+	if err != nil {
+		return nil, err
+	}
+
+	blessed, err := blessor.Bless(blessee.PublicID(), name, 24*time.Hour, caveats)
+
+	if err != nil {
+		return nil, verror.NotAuthorizedf("failed to bless id: %v", err)
+	}
+
+	if blessee, err = blessee.Derive(blessed); err != nil {
+		return nil, verror.Internalf("failed to derive private id: %v", err)
+	}
+	return blessee, nil
+}
diff --git a/services/wspr/wsprd/lib/identity_test.go b/services/wspr/wsprd/lib/identity_test.go
new file mode 100644
index 0000000..b7ccbad
--- /dev/null
+++ b/services/wspr/wsprd/lib/identity_test.go
@@ -0,0 +1,158 @@
+package lib
+
+import (
+	"bytes"
+	"io"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+	"time"
+
+	"veyron2"
+	"veyron2/rt"
+	"veyron2/security"
+)
+
+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 bufferCloser struct {
+	bytes.Buffer
+}
+
+func (*bufferCloser) Close() error {
+	return nil
+}
+
+type serializer struct {
+	data      bufferCloser
+	signature bufferCloser
+	hasData   bool
+}
+
+func (s *serializer) DataWriter() io.WriteCloser {
+	s.hasData = true
+	s.data.Reset()
+	return &s.data
+}
+
+func (s *serializer) SignatureWriter() io.WriteCloser {
+	s.signature.Reset()
+	return &s.signature
+}
+
+func (s *serializer) DataReader() io.Reader {
+	if s.hasData {
+		return &s.data
+	}
+	return nil
+}
+
+func (s *serializer) SignatureReader() io.Reader {
+	if s.hasData {
+		return &s.signature
+	}
+	return nil
+}
+
+func TestSavingAndFetchingIdentity(t *testing.T) {
+	r := rt.Init()
+	manager, err := NewIDManager(r, &serializer{})
+	if err != nil {
+		t.Fatalf("creating identity manager failed with: %v", err)
+	}
+	manager.AddAccount("google/user1", createChain(r, "google/user1"))
+	if err := manager.AddOrigin("sampleapp.com", "google/user1", nil); err != nil {
+		t.Fatalf("failed to generate id: %v", err)
+	}
+
+	if _, err := manager.Identity("sampleapp.com"); err != nil {
+		t.Errorf("failed to get  an identity for sampleapp.com: %v", err)
+	}
+
+	if _, err := manager.Identity("unknown.com"); err != OriginDoesNotExist {
+		t.Error("should not have found an identity for unknown.com")
+	}
+}
+
+func TestAccountsMatching(t *testing.T) {
+	r := rt.Init()
+	topLevelName := r.Identity().PublicID().Names()[0]
+	manager, err := NewIDManager(r, &serializer{})
+	if err != nil {
+		t.Fatalf("creating identity manager failed with: %v", err)
+	}
+	manager.AddAccount("google/user1", createChain(r, "google/user1"))
+	manager.AddAccount("google/user2", createChain(r, "google/user2"))
+	manager.AddAccount("facebook/user1", createChain(r, "facebook/user1"))
+
+	result := manager.AccountsMatching(security.PrincipalPattern(topLevelName + "/google/*"))
+	sort.StringSlice(result).Sort()
+	expected := []string{"google/user1", "google/user2"}
+	if !reflect.DeepEqual(result, expected) {
+		t.Errorf("unexpected result from AccountsMatching, expected :%v, got: %v", expected, result)
+	}
+}
+
+func TestGenerateIDWithUnknownBlesser(t *testing.T) {
+	r := rt.Init()
+	manager, err := NewIDManager(r, &serializer{})
+	if err != nil {
+		t.Fatalf("creating identity manager failed with: %v", err)
+	}
+
+	err = manager.AddOrigin("sampleapp.com", "google/user1", nil)
+
+	if err == nil {
+		t.Errorf("should have failed to generated an id blessed by google/user1")
+	}
+}
+
+func TestSerializingAndDeserializing(t *testing.T) {
+	r := rt.Init()
+	var serializer serializer
+
+	manager, err := NewIDManager(r, &serializer)
+	if err != nil {
+		t.Fatalf("creating identity manager failed with: %v", err)
+	}
+	manager.AddAccount("google/user1", createChain(r, "google/user1"))
+	if err = manager.AddOrigin("sampleapp.com", "google/user1", nil); err != nil {
+		t.Fatalf("failed to generate id: %v", err)
+	}
+
+	newManager, err := NewIDManager(r, &serializer)
+
+	if err != nil {
+		t.Fatalf("failed to deserialize data: %v", err)
+	}
+	if _, err := newManager.Identity("sampleapp.com"); err != nil {
+		t.Errorf("can't find the sampleapp.com identity: %v", err)
+	}
+
+	if err := newManager.AddOrigin("sampleapp2.com", "google/user1", nil); err != nil {
+		t.Errorf("failed to create sampleapp2.com identity: %v", err)
+	}
+}