Merge "veyron/services/identity: Add /blessing-root route to get the public key and names of the identity server's blessings."
diff --git a/services/identity/handlers/blessing_root.go b/services/identity/handlers/blessing_root.go
new file mode 100644
index 0000000..a0c2f7b
--- /dev/null
+++ b/services/identity/handlers/blessing_root.go
@@ -0,0 +1,72 @@
+package handlers
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	"veyron.io/veyron/veyron/services/identity/util"
+	"veyron.io/veyron/veyron2/security"
+)
+
+// BlessingRoot is an http.Handler implementation that renders the server's
+// blessing names and public key in a json string.
+type BlessingRoot struct {
+	P security.Principal
+}
+
+type BlessingRootResponse struct {
+	// Names of the blessings.
+	Names []string `json:"names"`
+	// Base64 der-encoded public key.
+	PublicKey string `json:"publicKey"`
+}
+
+// Cached response so we don't have to bless and encode every time somebody
+// hits this route.
+var cachedResponseJson []byte
+
+func (b BlessingRoot) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	if cachedResponseJson != nil {
+		respondJson(w, cachedResponseJson)
+		return
+	}
+
+	// Get the blessing names of the local principal.
+	// TODO(nlacasse,ataly,gauthamt): Make this easier to do. For now we
+	// have to bless a context with the same LocalPrincipal as ours.
+	ctx := security.NewContext(&security.ContextParams{
+		LocalPrincipal: b.P,
+	})
+	names := b.P.BlessingStore().Default().ForContext(ctx)
+
+	if len(names) == 0 {
+		util.HTTPServerError(w, fmt.Errorf("Could not get blessing name."))
+		return
+	}
+
+	der, err := b.P.PublicKey().MarshalBinary()
+	if err != nil {
+		util.HTTPServerError(w, err)
+		return
+	}
+	str := base64.URLEncoding.EncodeToString(der)
+
+	res, err := json.Marshal(BlessingRootResponse{
+		Names:     names,
+		PublicKey: str,
+	})
+	if err != nil {
+		util.HTTPServerError(w, err)
+		return
+	}
+
+	cachedResponseJson = res
+	respondJson(w, res)
+}
+
+func respondJson(w http.ResponseWriter, res []byte) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write(res)
+}
diff --git a/services/identity/handlers/handlers_test.go b/services/identity/handlers/handlers_test.go
index 09d2ec8..477761d 100644
--- a/services/identity/handlers/handlers_test.go
+++ b/services/identity/handlers/handlers_test.go
@@ -1,14 +1,18 @@
 package handlers
 
 import (
+	"encoding/base64"
+	"encoding/json"
 	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
 	"reflect"
+	"sort"
 	"testing"
 
 	"veyron.io/veyron/veyron2/security"
 
+	tsecurity "veyron.io/veyron/veyron/lib/testutil/security"
 	vsecurity "veyron.io/veyron/veyron/security"
 )
 
@@ -36,3 +40,40 @@
 		t.Errorf("Got %v, want %v", got, want)
 	}
 }
+
+func TestBlessingRoot(t *testing.T) {
+	blessingNames := []string{"test-blessing-name-1", "test-blessing-name-2"}
+	p := tsecurity.NewPrincipal(blessingNames...)
+
+	ts := httptest.NewServer(BlessingRoot{p})
+	defer ts.Close()
+	response, err := http.Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	dec := json.NewDecoder(response.Body)
+	var res BlessingRootResponse
+	if err := dec.Decode(&res); err != nil {
+		t.Fatal(err)
+	}
+
+	// Check that the names are correct.
+	sort.Strings(blessingNames)
+	sort.Strings(res.Names)
+	if !reflect.DeepEqual(res.Names, blessingNames) {
+		t.Errorf("Response has incorrect name. Got %v, want %v", res.Names, blessingNames)
+	}
+
+	// Check that the public key is correct.
+	gotMarshalled, err := base64.URLEncoding.DecodeString(res.PublicKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+	got, err := security.UnmarshalPublicKey(gotMarshalled)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if want := p.PublicKey(); !reflect.DeepEqual(got, want) {
+		t.Errorf("Response has incorrect public key.  Got %v, want %v", got, want)
+	}
+}
diff --git a/services/identity/identityd/main.go b/services/identity/identityd/main.go
index dec6d22..6c11891 100644
--- a/services/identity/identityd/main.go
+++ b/services/identity/identityd/main.go
@@ -41,7 +41,7 @@
 	// Flags controlling the HTTP server
 	httpaddr  = flag.String("httpaddr", "localhost:8125", "Address on which the HTTP server listens on.")
 	tlsconfig = flag.String("tlsconfig", "", "Comma-separated list of TLS certificate and private key files. This must be provided.")
-	host      = flag.String("host", defaultHost(), "Hostname the HTTP server listens on. This can be the name of the host running the webserver, but if running behind a NAT or load balancer, this should be the host name that clients will connect to. For example, if set to 'x.com', Veyron identities will have the IssuerName set to 'x.com' and clients can expect to find the public key of the signer at 'x.com/pubkey/'.")
+	host      = flag.String("host", defaultHost(), "Hostname the HTTP server listens on. This can be the name of the host running the webserver, but if running behind a NAT or load balancer, this should be the host name that clients will connect to. For example, if set to 'x.com', Veyron identities will have the IssuerName set to 'x.com' and clients can expect to find the public key of the signer at 'x.com/pubkey'.")
 
 	// Flag controlling auditing and revocation of Blessing operations.
 	sqlConfig = flag.String("sqlconfig", "", "Path to file containing go-sql-driver connection string of the following form: [username[:password]@][protocol[(address)]]/dbname")
@@ -93,7 +93,9 @@
 	}
 
 	// Setup handlers
-	http.Handle("/pubkey/", handlers.PublicKey{runtime.Principal().PublicKey()}) // public key of this server
+	// TODO(nlacasse,ataly,suharshs): Remove the 'pubkey' route if it's no longer needed.
+	http.Handle("/pubkey", handlers.PublicKey{runtime.Principal().PublicKey()}) // public key of this server
+	http.Handle("/blessing-root", handlers.BlessingRoot{runtime.Principal()})   // json-encoded public key and blessing names of this server
 	macaroonKey := make([]byte, 32)
 	if _, err := rand.Read(macaroonKey); err != nil {
 		vlog.Fatalf("macaroonKey generation failed: %v", err)
@@ -351,7 +353,7 @@
 <div class="well">
 This is a Veyron identity provider that provides blessings with the name prefix <mark>{{.Self}}</mark>.
 <br/>
-The public key of this provider is {{.Self.PublicKey}}, which is available in <a class="btn btn-xs btn-primary" href="/pubkey/">DER</a> encoded
+The public key of this provider is {{.Self.PublicKey}}, which is available in <a class="btn btn-xs btn-primary" href="/pubkey">DER</a> encoded
 <a href="http://en.wikipedia.org/wiki/X.690#DER_encoding">format</a>.
 </div>