blob: 9220b9796fa471dce4811faa5df5ceeb7642199d [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package handlers
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"v.io/v23/security"
"v.io/v23/vom"
"v.io/x/ref/services/identity/internal/util"
)
// 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
}
// 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.
var names []string
for n, _ := range b.P.BlessingsInfo(b.P.BlessingStore().Default()) {
names = append(names, n)
}
if len(names) == 0 {
util.HTTPServerError(w, fmt.Errorf("Could not get default blessing name"))
return
}
// TODO(nlacasse,ashankar,ataly): The following line is a HACK. It
// marshals the public key of the *root* of the blessing chain, rather
// than the public key of the principal itself.
//
// We do this because the identity server is expected to be
// self-signed, and the javascript tests were breaking when the
// identity server is run with a blessing like test/child.
//
// Once this issue is resolved, delete the following line and uncomment
// the block below it.
der, err := rootPublicKey(b.P.BlessingStore().Default())
if err != nil {
util.HTTPServerError(w, err)
return
}
//der, err := b.P.PublicKey().MarshalBinary()
//if err != nil {
// util.HTTPServerError(w, err)
// return
//}
str := base64.URLEncoding.EncodeToString(der)
// TODO(suharshs): Ideally this struct would be BlessingRootResponse but vdl does
// not currently allow field annotations. Once those are allowed, then use that
// here.
rootInfo := struct {
Names []string `json:"names"`
PublicKey string `json:"publicKey"`
}{
Names: names,
PublicKey: str,
}
res, err := json.Marshal(rootInfo)
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)
}
// Circuitious route to obtain the certificate chain because the use
// of security.MarshalBlessings is discouraged.
func rootPublicKey(b security.Blessings) ([]byte, error) {
data, err := vom.Encode(b)
if err != nil {
return nil, fmt.Errorf("malformed Blessings: %v", err)
}
var wire security.WireBlessings
if err := vom.Decode(data, &wire); err != nil {
return nil, fmt.Errorf("malformed WireBlessings: %v", err)
}
return wire.CertificateChains[0][0].PublicKey, nil
}