"veyron/services/identity": BlessUsingAccessToken returns email

Modified BlessUsingAccessToken to along with the blessing also
return the email for which the blessing was generated. The email
provides clients a means to tag the blessing (e.g. WSPR would
use the email while adding the Blessing to the identity mananger).

Additionally, also updated the implementation to use the new
security model when possible.

Change-Id: Iab180ff412769a507f8117a4eaf375cce0829a9a
diff --git a/services/identity/blesser/oauth.go b/services/identity/blesser/oauth.go
index 9463692..be6dd9f 100644
--- a/services/identity/blesser/oauth.go
+++ b/services/identity/blesser/oauth.go
@@ -64,17 +64,17 @@
 	})
 }
 
-func (b *googleOAuth) BlessUsingAccessToken(ctx ipc.ServerContext, accesstoken string) (vdlutil.Any, error) {
+func (b *googleOAuth) BlessUsingAccessToken(ctx ipc.ServerContext, accesstoken string) (vdlutil.Any, string, error) {
 	if len(b.accessTokenClients) == 0 {
-		return nil, fmt.Errorf("server not configured for blessing based on access tokens")
+		return nil, "", fmt.Errorf("server not configured for blessing based on access tokens")
 	}
 	// URL from: https://developers.google.com/accounts/docs/OAuth2UserAgent#validatetoken
 	tokeninfo, err := http.Get("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + accesstoken)
 	if err != nil {
-		return nil, fmt.Errorf("unable to use token: %v", err)
+		return nil, "", fmt.Errorf("unable to use token: %v", err)
 	}
 	if tokeninfo.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf("unable to verify access token: %v", tokeninfo.StatusCode)
+		return nil, "", fmt.Errorf("unable to verify access token: %v", tokeninfo.StatusCode)
 	}
 	// tokeninfo contains a JSON-encoded struct
 	var token struct {
@@ -88,7 +88,7 @@
 		AccessType    string `json:"access_type"`
 	}
 	if err := json.NewDecoder(tokeninfo.Body).Decode(&token); err != nil {
-		return "", fmt.Errorf("invalid JSON response from Google's tokeninfo API: %v", err)
+		return nil, "", fmt.Errorf("invalid JSON response from Google's tokeninfo API: %v", err)
 	}
 	audienceMatch := false
 	for _, c := range b.accessTokenClients {
@@ -99,31 +99,64 @@
 	}
 	if !audienceMatch {
 		vlog.Infof("Got access token [%+v], wanted one of client ids %v", token, b.accessTokenClients)
-		return "", fmt.Errorf("token not meant for this purpose, confused deputy? https://developers.google.com/accounts/docs/OAuth2UserAgent#validatetoken")
+		return nil, "", fmt.Errorf("token not meant for this purpose, confused deputy? https://developers.google.com/accounts/docs/OAuth2UserAgent#validatetoken")
 	}
 	if !token.VerifiedEmail {
-		return nil, fmt.Errorf("email not verified")
+		return nil, "", fmt.Errorf("email not verified")
+	}
+	if ctx.LocalPrincipal() == nil || ctx.RemoteBlessings() == nil {
+		// TODO(ataly, ashankar): Old security model, remove this block.
+		return b.blessOldModel(ctx, token.Email)
 	}
 	return b.bless(ctx, token.Email)
 }
 
-func (b *googleOAuth) bless(ctx ipc.ServerContext, name string) (vdlutil.Any, error) {
+func (b *googleOAuth) bless(ctx ipc.ServerContext, email string) (vdlutil.Any, string, error) {
+	var caveat security.Caveat
+	var err error
+	if b.revocationManager != nil {
+		// TODO(ataly, ashankar): Update the RevocationManager so that it uses the
+		// new security model.
+		revocationCaveat, err := b.revocationManager.NewCaveat(b.rt.Identity().PublicID(), b.dischargerLocation)
+		if err != nil {
+			return nil, "", err
+		}
+		caveat, err = security.NewCaveat(revocationCaveat)
+	} else {
+		caveat, err = security.ExpiryCaveat(time.Now().Add(b.duration))
+	}
+	if err != nil {
+		return nil, "", err
+	}
+	blessing, err := ctx.LocalPrincipal().Bless(ctx.RemoteBlessings().PublicKey(), ctx.LocalBlessings(), email, caveat)
+	if err != nil {
+		return nil, "", err
+	}
+	return blessing, email, nil
+}
+
+// DEPRECATED
+// TODO(ataly, ashankar): Remove this method once we get rid of the old security model.
+func (b *googleOAuth) blessOldModel(ctx ipc.ServerContext, name string) (vdlutil.Any, string, error) {
 	if len(b.domain) > 0 && !strings.HasSuffix(name, "@"+b.domain) {
-		return nil, fmt.Errorf("blessings for name %q are not allowed due to domain restriction", name)
+		return nil, "", fmt.Errorf("blessings for name %q are not allowed due to domain restriction", name)
 	}
 	self := b.rt.Identity()
 	var err error
 	// Use the blessing that was used to authenticate with the client to bless it.
 	if self, err = self.Derive(ctx.LocalID()); err != nil {
-		return nil, err
+		return nil, "", err
 	}
 	var revocationCaveat security.ThirdPartyCaveat
 	if b.revocationManager != nil {
 		revocationCaveat, err = b.revocationManager.NewCaveat(b.rt.Identity().PublicID(), b.dischargerLocation)
 		if err != nil {
-			return nil, err
+			return nil, "", err
 		}
 	}
-
-	return revocation.Bless(self, ctx.RemoteID(), name, b.duration, nil, revocationCaveat)
+	blessing, err := revocation.Bless(self, ctx.RemoteID(), name, b.duration, nil, revocationCaveat)
+	if err != nil {
+		return nil, "", err
+	}
+	return blessing, name, nil
 }
diff --git a/services/identity/identity.vdl b/services/identity/identity.vdl
index bec7d91..faad788 100644
--- a/services/identity/identity.vdl
+++ b/services/identity/identity.vdl
@@ -14,13 +14,10 @@
 // veyron virtual circuit).
 // Thus, if Mallory possesses the access token associated with Alice's account,
 // she may be able to obtain a blessing with Alice's name on it.
-//
-// TODO(ashankar): Update this to use the new security model:
-// (blessing security.WireBlessing, error)
 type OAuthBlesser interface {
   // BlessUsingAccessToken uses the provided access token to obtain the email
-  // address and returns a blessing.
-  BlessUsingAccessToken(token string) (blessing any, err error)
+  // address and returns a blessing along with the email address.
+  BlessUsingAccessToken(token string) (blessing any, email string, err error)
 }
 
 // MacaroonBlesser returns a blessing given the provided macaroon string.
diff --git a/services/identity/identity.vdl.go b/services/identity/identity.vdl.go
index a947249..2525ee7 100644
--- a/services/identity/identity.vdl.go
+++ b/services/identity/identity.vdl.go
@@ -31,16 +31,13 @@
 // veyron virtual circuit).
 // Thus, if Mallory possesses the access token associated with Alice's account,
 // she may be able to obtain a blessing with Alice's name on it.
-//
-// TODO(ashankar): Update this to use the new security model:
-// (blessing security.WireBlessing, error)
 // OAuthBlesser is the interface the client binds and uses.
 // OAuthBlesser_ExcludingUniversal is the interface without internal framework-added methods
 // to enable embedding without method collisions.  Not to be used directly by clients.
 type OAuthBlesser_ExcludingUniversal interface {
 	// BlessUsingAccessToken uses the provided access token to obtain the email
-	// address and returns a blessing.
-	BlessUsingAccessToken(ctx _gen_context.T, token string, opts ..._gen_ipc.CallOpt) (reply _gen_vdlutil.Any, err error)
+	// address and returns a blessing along with the email address.
+	BlessUsingAccessToken(ctx _gen_context.T, token string, opts ..._gen_ipc.CallOpt) (blessing _gen_vdlutil.Any, email string, err error)
 }
 type OAuthBlesser interface {
 	_gen_ipc.UniversalServiceMethods
@@ -51,8 +48,8 @@
 type OAuthBlesserService interface {
 
 	// BlessUsingAccessToken uses the provided access token to obtain the email
-	// address and returns a blessing.
-	BlessUsingAccessToken(context _gen_ipc.ServerContext, token string) (reply _gen_vdlutil.Any, err error)
+	// address and returns a blessing along with the email address.
+	BlessUsingAccessToken(context _gen_ipc.ServerContext, token string) (blessing _gen_vdlutil.Any, email string, err error)
 }
 
 // BindOAuthBlesser returns the client stub implementing the OAuthBlesser
@@ -102,12 +99,12 @@
 	return _gen_veyron2.RuntimeFromContext(ctx).Client()
 }
 
-func (__gen_c *clientStubOAuthBlesser) BlessUsingAccessToken(ctx _gen_context.T, token string, opts ..._gen_ipc.CallOpt) (reply _gen_vdlutil.Any, err error) {
+func (__gen_c *clientStubOAuthBlesser) BlessUsingAccessToken(ctx _gen_context.T, token string, opts ..._gen_ipc.CallOpt) (blessing _gen_vdlutil.Any, email string, err error) {
 	var call _gen_ipc.Call
 	if call, err = __gen_c.client(ctx).StartCall(ctx, __gen_c.name, "BlessUsingAccessToken", []interface{}{token}, opts...); err != nil {
 		return
 	}
-	if ierr := call.Finish(&reply, &err); ierr != nil {
+	if ierr := call.Finish(&blessing, &email, &err); ierr != nil {
 		err = ierr
 	}
 	return
@@ -173,6 +170,7 @@
 		},
 		OutArgs: []_gen_ipc.MethodArgument{
 			{Name: "blessing", Type: 65},
+			{Name: "email", Type: 3},
 			{Name: "err", Type: 66},
 		},
 	}
@@ -201,8 +199,8 @@
 	return
 }
 
-func (__gen_s *ServerStubOAuthBlesser) BlessUsingAccessToken(call _gen_ipc.ServerCall, token string) (reply _gen_vdlutil.Any, err error) {
-	reply, err = __gen_s.service.BlessUsingAccessToken(call, token)
+func (__gen_s *ServerStubOAuthBlesser) BlessUsingAccessToken(call _gen_ipc.ServerCall, token string) (blessing _gen_vdlutil.Any, email string, err error) {
+	blessing, email, err = __gen_s.service.BlessUsingAccessToken(call, token)
 	return
 }