forked from TrueCloudLab/certificates
Add method to get all the certs.
This commit is contained in:
parent
10978630e5
commit
37149ed3ea
2 changed files with 86 additions and 0 deletions
31
api/api.go
31
api/api.go
|
@ -25,6 +25,7 @@ type Authority interface {
|
||||||
Renew(cert *x509.Certificate) (*x509.Certificate, *x509.Certificate, error)
|
Renew(cert *x509.Certificate) (*x509.Certificate, *x509.Certificate, error)
|
||||||
GetProvisioners(cursor string, limit int) ([]*authority.Provisioner, string, error)
|
GetProvisioners(cursor string, limit int) ([]*authority.Provisioner, string, error)
|
||||||
GetEncryptedKey(kid string) (string, error)
|
GetEncryptedKey(kid string) (string, error)
|
||||||
|
GetFederation(cert *x509.Certificate) ([]*x509.Certificate, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certificate wraps a *x509.Certificate and adds the json.Marshaler interface.
|
// Certificate wraps a *x509.Certificate and adds the json.Marshaler interface.
|
||||||
|
@ -186,6 +187,11 @@ type SignResponse struct {
|
||||||
TLS *tls.ConnectionState `json:"-"`
|
TLS *tls.ConnectionState `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FederationResponse is the response object of the federation request.
|
||||||
|
type FederationResponse struct {
|
||||||
|
Certificates []Certificate `json:"crts"`
|
||||||
|
}
|
||||||
|
|
||||||
// caHandler is the type used to implement the different CA HTTP endpoints.
|
// caHandler is the type used to implement the different CA HTTP endpoints.
|
||||||
type caHandler struct {
|
type caHandler struct {
|
||||||
Authority Authority
|
Authority Authority
|
||||||
|
@ -205,6 +211,7 @@ func (h *caHandler) Route(r Router) {
|
||||||
r.MethodFunc("POST", "/renew", h.Renew)
|
r.MethodFunc("POST", "/renew", h.Renew)
|
||||||
r.MethodFunc("GET", "/provisioners", h.Provisioners)
|
r.MethodFunc("GET", "/provisioners", h.Provisioners)
|
||||||
r.MethodFunc("GET", "/provisioners/{kid}/encrypted-key", h.ProvisionerKey)
|
r.MethodFunc("GET", "/provisioners/{kid}/encrypted-key", h.ProvisionerKey)
|
||||||
|
r.MethodFunc("GET", "/federation", h.Federation)
|
||||||
// For compatibility with old code:
|
// For compatibility with old code:
|
||||||
r.MethodFunc("POST", "/re-sign", h.Renew)
|
r.MethodFunc("POST", "/re-sign", h.Renew)
|
||||||
}
|
}
|
||||||
|
@ -320,6 +327,30 @@ func (h *caHandler) ProvisionerKey(w http.ResponseWriter, r *http.Request) {
|
||||||
JSON(w, &ProvisionerKeyResponse{key})
|
JSON(w, &ProvisionerKeyResponse{key})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Federation returns all the public certificates in the federation.
|
||||||
|
func (h *caHandler) Federation(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 {
|
||||||
|
WriteError(w, BadRequest(errors.New("missing peer certificate")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
federated, err := h.Authority.GetFederation(r.TLS.PeerCertificates[0])
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, Forbidden(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
certs := make([]Certificate, len(federated))
|
||||||
|
for i := range federated {
|
||||||
|
certs[i] = Certificate{federated[i]}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
JSON(w, &FederationResponse{
|
||||||
|
Certificates: certs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func parseCursor(r *http.Request) (cursor string, limit int, err error) {
|
func parseCursor(r *http.Request) (cursor string, limit int, err error) {
|
||||||
q := r.URL.Query()
|
q := r.URL.Query()
|
||||||
cursor = q.Get("cursor")
|
cursor = q.Get("cursor")
|
||||||
|
|
|
@ -392,6 +392,7 @@ type mockAuthority struct {
|
||||||
renew func(cert *x509.Certificate) (*x509.Certificate, *x509.Certificate, error)
|
renew func(cert *x509.Certificate) (*x509.Certificate, *x509.Certificate, error)
|
||||||
getProvisioners func(nextCursor string, limit int) ([]*authority.Provisioner, string, error)
|
getProvisioners func(nextCursor string, limit int) ([]*authority.Provisioner, string, error)
|
||||||
getEncryptedKey func(kid string) (string, error)
|
getEncryptedKey func(kid string) (string, error)
|
||||||
|
getFederation func(cert *x509.Certificate) ([]*x509.Certificate, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockAuthority) Authorize(ott string) ([]interface{}, error) {
|
func (m *mockAuthority) Authorize(ott string) ([]interface{}, error) {
|
||||||
|
@ -443,6 +444,13 @@ func (m *mockAuthority) GetEncryptedKey(kid string) (string, error) {
|
||||||
return m.ret1.(string), m.err
|
return m.ret1.(string), m.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockAuthority) GetFederation(cert *x509.Certificate) ([]*x509.Certificate, error) {
|
||||||
|
if m.getFederation != nil {
|
||||||
|
return m.getFederation(cert)
|
||||||
|
}
|
||||||
|
return m.ret1.([]*x509.Certificate), m.err
|
||||||
|
}
|
||||||
|
|
||||||
func Test_caHandler_Route(t *testing.T) {
|
func Test_caHandler_Route(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
Authority Authority
|
Authority Authority
|
||||||
|
@ -812,3 +820,50 @@ func Test_caHandler_ProvisionerKey(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_caHandler_Federation(t *testing.T) {
|
||||||
|
cs := &tls.ConnectionState{
|
||||||
|
PeerCertificates: []*x509.Certificate{parseCertificate(certPEM)},
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
tls *tls.ConnectionState
|
||||||
|
cert *x509.Certificate
|
||||||
|
root *x509.Certificate
|
||||||
|
err error
|
||||||
|
statusCode int
|
||||||
|
}{
|
||||||
|
{"ok", cs, parseCertificate(certPEM), parseCertificate(rootPEM), nil, http.StatusCreated},
|
||||||
|
{"no tls", nil, nil, nil, nil, http.StatusBadRequest},
|
||||||
|
{"no peer certificates", &tls.ConnectionState{}, nil, nil, nil, http.StatusBadRequest},
|
||||||
|
{"renew error", cs, nil, nil, fmt.Errorf("an error"), http.StatusForbidden},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []byte(`{"crts":["` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n"]}`)
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
h := New(&mockAuthority{ret1: []*x509.Certificate{tt.root}, err: tt.err}).(*caHandler)
|
||||||
|
req := httptest.NewRequest("GET", "http://example.com/federation", nil)
|
||||||
|
req.TLS = tt.tls
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
h.Federation(w, req)
|
||||||
|
res := w.Result()
|
||||||
|
|
||||||
|
if res.StatusCode != tt.statusCode {
|
||||||
|
t.Errorf("caHandler.Root StatusCode = %d, wants %d", res.StatusCode, tt.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("caHandler.Root unexpected error = %v", err)
|
||||||
|
}
|
||||||
|
if tt.statusCode < http.StatusBadRequest {
|
||||||
|
if !bytes.Equal(bytes.TrimSpace(body), expected) {
|
||||||
|
t.Errorf("caHandler.Root Body = %s, wants %s", body, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue