services/identity: make the mock oauth email flag-configurable & other changes

This is needed to use identityd_test for a test GCE instance that mimics
production.
Other changes in this cl:

- moving v23.Init at the top of main in identityd_test s.t. the flag parsing
  happens inside v23.Init

- fix error messages when SplitHostPort fails

- dump the output of tls cert generation when it fails (to help the user figure
  out what went wrong).

Change-Id: I45fee0f6222431035ffa924823be9416640ef236
diff --git a/services/identity/identitylib/test_identityd.go b/services/identity/identitylib/test_identityd.go
index 53c8587..1559091 100644
--- a/services/identity/identitylib/test_identityd.go
+++ b/services/identity/identitylib/test_identityd.go
@@ -55,7 +55,7 @@
 		}
 		host, _, err := net.SplitHostPort(addr)
 		if err != nil {
-			return fmt.Errorf("Failed to parse %q: %v", httpAddr, err)
+			return fmt.Errorf("Failed to parse %q: %v", addr, err)
 		}
 		certFile, keyFile, err := util.WriteCertAndKey(host, duration)
 		if err != nil {
@@ -79,7 +79,7 @@
 
 	auditor, reader := auditor.NewMockBlessingAuditor()
 	revocationManager := revocation.NewMockRevocationManager()
-	oauthProvider := oauth.NewMockOAuth()
+	oauthProvider := oauth.NewMockOAuth("testemail@example.com")
 
 	params := blesser.OAuthBlesserParams{
 		OAuthProvider:     oauthProvider,
diff --git a/services/identity/internal/blesser/oauth_test.go b/services/identity/internal/blesser/oauth_test.go
index 48b569f..91c5a23 100644
--- a/services/identity/internal/blesser/oauth_test.go
+++ b/services/identity/internal/blesser/oauth_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 	"time"
 
@@ -15,13 +16,18 @@
 	"v.io/v23/security"
 )
 
+func join(elements ...string) string {
+	return strings.Join(elements, security.ChainSeparator)
+}
+
 func TestOAuthBlesser(t *testing.T) {
 	var (
 		provider, user = testutil.NewPrincipal(), testutil.NewPrincipal()
 		ctx, call      = fakeContextAndCall(provider, user)
 	)
+	mockEmail := "testemail@example.com"
 	blesser := NewOAuthBlesserServer(OAuthBlesserParams{
-		OAuthProvider:    oauth.NewMockOAuth(),
+		OAuthProvider:    oauth.NewMockOAuth(mockEmail),
 		BlessingDuration: time.Hour,
 	})
 
@@ -30,7 +36,7 @@
 		t.Errorf("BlessUsingAccessToken failed: %v", err)
 	}
 
-	wantExtension := "users" + security.ChainSeparator + oauth.MockEmail + security.ChainSeparator + oauth.MockClient
+	wantExtension := join("users", mockEmail, oauth.MockClient)
 	if extension != wantExtension {
 		t.Errorf("got extension: %s, want: %s", extension, wantExtension)
 	}
@@ -45,13 +51,13 @@
 		t.Errorf("Got blessing with info %v, want nil", got)
 	}
 	// But once it recognizes the provider, it should see exactly the name
-	// "provider/testemail@google.com/test-client".
+	// "provider/testemail@example.com/test-client".
 	user.AddToRoots(b)
 	binfo := user.BlessingsInfo(b)
 	if num := len(binfo); num != 1 {
 		t.Errorf("Got blessings with %d names, want exactly one name", num)
 	}
-	if _, ok := binfo["provider"+security.ChainSeparator+wantExtension]; !ok {
+	if _, ok := binfo[join("provider", wantExtension)]; !ok {
 		t.Errorf("BlessingsInfo %v does not have name %s", binfo, wantExtension)
 	}
 }
diff --git a/services/identity/internal/identityd_test/main.go b/services/identity/internal/identityd_test/main.go
index ca59165..77672a5 100644
--- a/services/identity/internal/identityd_test/main.go
+++ b/services/identity/internal/identityd_test/main.go
@@ -33,11 +33,13 @@
 	assetsPrefix     = flag.String("assets-prefix", "", "host serving the web assets for the identity server")
 	mountPrefix      = flag.String("mount-prefix", "identity", "mount name prefix to use. May be rooted.")
 	browser          = flag.Bool("browser", false, "whether to open a browser caveat selector")
+	oauthEmail       = flag.String("oauth-email", "testemail@example.com", "Username for the mock oauth to put in the returned blessings")
 )
 
 func main() {
 	flag.Usage = usage
-	flag.Parse()
+	ctx, shutdown := v23.Init()
+	defer shutdown()
 
 	// Duration to use for tls cert and blessing duration.
 	duration := 365 * 24 * time.Hour
@@ -50,7 +52,10 @@
 		}
 		host, _, err := net.SplitHostPort(addr)
 		if err != nil {
-			vlog.Fatalf("Failed to parse %q: %v", httpAddr, err)
+			// NOTE(caprita): The (non-test) identityd binary
+			// accepts an address with no port.  Should this test
+			// binary do the same instead?
+			vlog.Fatalf("Failed to parse %q: %v", addr, err)
 		}
 		certFile, keyFile, err := util.WriteCertAndKey(host, duration)
 		if err != nil {
@@ -63,7 +68,7 @@
 
 	auditor, reader := auditor.NewMockBlessingAuditor()
 	revocationManager := revocation.NewMockRevocationManager()
-	oauthProvider := oauth.NewMockOAuth()
+	oauthProvider := oauth.NewMockOAuth(*oauthEmail)
 
 	params := blesser.OAuthBlesserParams{
 		OAuthProvider:     oauthProvider,
@@ -71,9 +76,6 @@
 		RevocationManager: revocationManager,
 	}
 
-	ctx, shutdown := v23.Init()
-	defer shutdown()
-
 	caveatSelector := caveats.NewMockCaveatSelector()
 	if *browser {
 		bname, _, err := util.RootCertificateDetails(v23.GetPrincipal(ctx).BlessingStore().Default())
diff --git a/services/identity/internal/oauth/mockoauth.go b/services/identity/internal/oauth/mockoauth.go
index c122af7..3a0e828 100644
--- a/services/identity/internal/oauth/mockoauth.go
+++ b/services/identity/internal/oauth/mockoauth.go
@@ -4,16 +4,15 @@
 
 package oauth
 
-const (
-	MockEmail  = "testemail@google.com"
-	MockClient = "test-client"
-)
+const MockClient = "test-client"
 
 // mockOAuth is a mock OAuthProvider for use in tests.
-type mockOAuth struct{}
+type mockOAuth struct {
+	email string
+}
 
-func NewMockOAuth() OAuthProvider {
-	return &mockOAuth{}
+func NewMockOAuth(mockEmail string) OAuthProvider {
+	return &mockOAuth{email: mockEmail}
 }
 
 func (m *mockOAuth) AuthURL(redirectUrl string, state string, _ AuthURLApproval) string {
@@ -21,9 +20,9 @@
 }
 
 func (m *mockOAuth) ExchangeAuthCodeForEmail(string, string) (string, error) {
-	return MockEmail, nil
+	return m.email, nil
 }
 
 func (m *mockOAuth) GetEmailAndClientName(string, []AccessTokenClient) (string, string, error) {
-	return MockEmail, MockClient, nil
+	return m.email, MockClient, nil
 }
diff --git a/services/identity/internal/util/certs.go b/services/identity/internal/util/certs.go
index 3c6e7b8..c6aeba6 100644
--- a/services/identity/internal/util/certs.go
+++ b/services/identity/internal/util/certs.go
@@ -26,7 +26,8 @@
 	generateCertFile := filepath.Join(strings.TrimSpace(string(output)), "generate_cert.go")
 	generateCertCmd := exec.Command("go", "run", generateCertFile, "--host", host, "--duration", duration.String())
 	generateCertCmd.Dir = tmpDir
-	if err := generateCertCmd.Run(); err != nil {
+	if output, err := generateCertCmd.CombinedOutput(); err != nil {
+		fmt.Fprintf(os.Stderr, "%v failed:\n%s\n", generateCertCmd.Args, output)
 		return "", "", fmt.Errorf("Could not generate key and cert: %v", err)
 	}
 	return filepath.Join(tmpDir, "cert.pem"), filepath.Join(tmpDir, "key.pem"), nil