/
blessing_root.go
116 lines (103 loc) · 2.97 KB
/
blessing_root.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// 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"
"net/http"
"strings"
"sync"
"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 (
cacheMu sync.RWMutex
cachedResponseJSON []byte
cachedResponseBase64VOM []byte
)
func (b BlessingRoot) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch format := r.FormValue("output"); format {
case "base64vom":
b.base64vomResponse(w, r)
default:
b.jsonResponse(w, r)
}
}
func (b BlessingRoot) base64vomResponse(w http.ResponseWriter, r *http.Request) {
cacheMu.RLock()
if cachedResponseBase64VOM != nil {
respondString(w, "text/plain", cachedResponseBase64VOM)
cacheMu.RUnlock()
return
}
cacheMu.RUnlock()
blessings, _ := b.P.BlessingStore().Default()
roots := security.RootBlessings(blessings)
strs := make([]string, len(roots))
for i, r := range roots {
v, err := vom.Encode(r)
if err != nil {
util.HTTPServerError(w, err)
}
strs[i] = base64.URLEncoding.EncodeToString(v)
}
ret := []byte(strings.Join(strs, "\n"))
cacheMu.Lock()
cachedResponseBase64VOM = ret
cacheMu.Unlock()
respondString(w, "text/plain", cachedResponseBase64VOM)
}
func (b BlessingRoot) jsonResponse(w http.ResponseWriter, r *http.Request) {
cacheMu.RLock()
if cachedResponseJSON != nil {
respondString(w, "application/json", cachedResponseJSON)
cacheMu.RUnlock()
return
}
cacheMu.RUnlock()
// The identity service itself is blessed by a more protected key.
// Use the root certificate as the identity provider.
//
// TODO(ashankar): This is making the assumption that the identity
// service has a single blessing, which may not be true in general.
// Revisit this.
def, _ := b.P.BlessingStore().Default()
name, der, err := util.RootCertificateDetails(def)
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: []string{name},
PublicKey: str,
}
res, err := json.Marshal(rootInfo)
if err != nil {
util.HTTPServerError(w, err)
return
}
cacheMu.Lock()
cachedResponseJSON = res
cacheMu.Unlock()
respondString(w, "application/json", res)
}
func respondString(w http.ResponseWriter, contentType string, res []byte) {
w.Header().Set("Content-Type", contentType)
w.Write(res) //nolint:errcheck
}