Rename SSH methods.

This commit is contained in:
Mariano Cano 2019-10-08 18:35:28 -07:00 committed by max furman
parent b5bc249e1c
commit d08db4df23
7 changed files with 94 additions and 85 deletions

View file

@ -251,15 +251,15 @@ func (h *caHandler) Route(r Router) {
r.MethodFunc("GET", "/roots", h.Roots)
r.MethodFunc("GET", "/federation", h.Federation)
// SSH CA
r.MethodFunc("POST", "/ssh/sign", h.SignSSH)
r.MethodFunc("GET", "/ssh/keys", h.SSHKeys)
r.MethodFunc("GET", "/ssh/federation", h.SSHFederatedKeys)
r.MethodFunc("POST", "/ssh/sign", h.SSHSign)
r.MethodFunc("GET", "/ssh/roots", h.SSHRoots)
r.MethodFunc("GET", "/ssh/federation", h.SSHFederation)
r.MethodFunc("POST", "/ssh/config", h.SSHConfig)
r.MethodFunc("POST", "/ssh/config/{type}", h.SSHConfig)
// For compatibility with old code:
r.MethodFunc("POST", "/re-sign", h.Renew)
r.MethodFunc("POST", "/sign-ssh", h.SignSSH)
r.MethodFunc("POST", "/sign-ssh", h.SSHSign)
}
// Health is an HTTP handler that returns the status of the server.

View file

@ -513,7 +513,8 @@ type mockAuthority struct {
getEncryptedKey func(kid string) (string, error)
getRoots func() ([]*x509.Certificate, error)
getFederation func() ([]*x509.Certificate, error)
getSSHKeys func() (*authority.SSHKeys, error)
getSSHRoots func() (*authority.SSHKeys, error)
getSSHFederation func() (*authority.SSHKeys, error)
getSSHConfig func(typ string, data map[string]string) ([]templates.Output, error)
}
@ -620,9 +621,16 @@ func (m *mockAuthority) GetFederation() ([]*x509.Certificate, error) {
return m.ret1.([]*x509.Certificate), m.err
}
func (m *mockAuthority) GetSSHKeys() (*authority.SSHKeys, error) {
if m.getSSHKeys != nil {
return m.getSSHKeys()
func (m *mockAuthority) GetSSHRoots() (*authority.SSHKeys, error) {
if m.getSSHRoots != nil {
return m.getSSHRoots()
}
return m.ret1.(*authority.SSHKeys), m.err
}
func (m *mockAuthority) GetSSHFederation() (*authority.SSHKeys, error) {
if m.getSSHFederation != nil {
return m.getSSHFederation()
}
return m.ret1.(*authority.SSHKeys), m.err
}

View file

@ -17,13 +17,13 @@ import (
type SSHAuthority interface {
SignSSH(key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error)
SignSSHAddUser(key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error)
GetSSHKeys() (*authority.SSHKeys, error)
GetSSHFederatedKeys() (*authority.SSHKeys, error)
GetSSHRoots() (*authority.SSHKeys, error)
GetSSHFederation() (*authority.SSHKeys, error)
GetSSHConfig(typ string, data map[string]string) ([]templates.Output, error)
}
// SignSSHRequest is the request body of an SSH certificate request.
type SignSSHRequest struct {
// SSHSignRequest is the request body of an SSH certificate request.
type SSHSignRequest struct {
PublicKey []byte `json:"publicKey"` //base64 encoded
OTT string `json:"ott"`
CertType string `json:"certType,omitempty"`
@ -33,8 +33,8 @@ type SignSSHRequest struct {
AddUserPublicKey []byte `json:"addUserPublicKey,omitempty"`
}
// Validate validates the SignSSHRequest.
func (s *SignSSHRequest) Validate() error {
// Validate validates the SSHSignRequest.
func (s *SSHSignRequest) Validate() error {
switch {
case s.CertType != "" && s.CertType != provisioner.SSHUserCert && s.CertType != provisioner.SSHHostCert:
return errors.Errorf("unknown certType %s", s.CertType)
@ -47,15 +47,15 @@ func (s *SignSSHRequest) Validate() error {
}
}
// SignSSHResponse is the response object that returns the SSH certificate.
type SignSSHResponse struct {
// SSHSignResponse is the response object that returns the SSH certificate.
type SSHSignResponse struct {
Certificate SSHCertificate `json:"crt"`
AddUserCertificate *SSHCertificate `json:"addUserCrt,omitempty"`
}
// SSHKeysResponse represents the response object that returns the SSH user and
// SSHRootsResponse represents the response object that returns the SSH user and
// host keys.
type SSHKeysResponse struct {
type SSHRootsResponse struct {
UserKeys []SSHPublicKey `json:"userKey,omitempty"`
HostKeys []SSHPublicKey `json:"hostKey,omitempty"`
}
@ -170,11 +170,11 @@ type SSHConfigResponse struct {
HostTemplates []Template `json:"hostTemplates,omitempty"`
}
// SignSSH is an HTTP handler that reads an SignSSHRequest with a one-time-token
// SSHSign is an HTTP handler that reads an SignSSHRequest with a one-time-token
// (ott) from the body and creates a new SSH certificate with the information in
// the request.
func (h *caHandler) SignSSH(w http.ResponseWriter, r *http.Request) {
var body SignSSHRequest
func (h *caHandler) SSHSign(w http.ResponseWriter, r *http.Request) {
var body SSHSignRequest
if err := ReadJSON(r.Body, &body); err != nil {
WriteError(w, BadRequest(errors.Wrap(err, "error reading request body")))
return
@ -232,16 +232,16 @@ func (h *caHandler) SignSSH(w http.ResponseWriter, r *http.Request) {
}
w.WriteHeader(http.StatusCreated)
JSON(w, &SignSSHResponse{
JSON(w, &SSHSignResponse{
Certificate: SSHCertificate{cert},
AddUserCertificate: addUserCertificate,
})
}
// SSHKeys is an HTTP handler that returns the SSH public keys for user and host
// SSHRoots is an HTTP handler that returns the SSH public keys for user and host
// certificates.
func (h *caHandler) SSHKeys(w http.ResponseWriter, r *http.Request) {
keys, err := h.Authority.GetSSHKeys()
func (h *caHandler) SSHRoots(w http.ResponseWriter, r *http.Request) {
keys, err := h.Authority.GetSSHRoots()
if err != nil {
WriteError(w, InternalServerError(err))
return
@ -252,7 +252,7 @@ func (h *caHandler) SSHKeys(w http.ResponseWriter, r *http.Request) {
return
}
resp := new(SSHKeysResponse)
resp := new(SSHRootsResponse)
for _, k := range keys.HostKeys {
resp.HostKeys = append(resp.HostKeys, SSHPublicKey{PublicKey: k})
}
@ -263,10 +263,10 @@ func (h *caHandler) SSHKeys(w http.ResponseWriter, r *http.Request) {
JSON(w, resp)
}
// SSHFederatedKeys is an HTTP handler that returns the federated SSH public
// keys for user and host certificates.
func (h *caHandler) SSHFederatedKeys(w http.ResponseWriter, r *http.Request) {
keys, err := h.Authority.GetSSHFederatedKeys()
// SSHFederation is an HTTP handler that returns the federated SSH public keys
// for user and host certificates.
func (h *caHandler) SSHFederation(w http.ResponseWriter, r *http.Request) {
keys, err := h.Authority.GetSSHFederation()
if err != nil {
WriteError(w, NotFound(err))
return
@ -277,7 +277,7 @@ func (h *caHandler) SSHFederatedKeys(w http.ResponseWriter, r *http.Request) {
return
}
resp := new(SSHKeysResponse)
resp := new(SSHRootsResponse)
for _, k := range keys.HostKeys {
resp.HostKeys = append(resp.HostKeys, SSHPublicKey{PublicKey: k})
}

View file

@ -219,7 +219,7 @@ func TestSignSSHRequest_Validate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &SignSSHRequest{
s := &SSHSignRequest{
PublicKey: tt.fields.PublicKey,
OTT: tt.fields.OTT,
CertType: tt.fields.CertType,
@ -235,7 +235,7 @@ func TestSignSSHRequest_Validate(t *testing.T) {
}
}
func Test_caHandler_SignSSH(t *testing.T) {
func Test_caHandler_SSHSign(t *testing.T) {
user, err := getSignedUserCertificate()
assert.FatalError(t, err)
host, err := getSignedHostCertificate()
@ -244,17 +244,17 @@ func Test_caHandler_SignSSH(t *testing.T) {
userB64 := base64.StdEncoding.EncodeToString(user.Marshal())
hostB64 := base64.StdEncoding.EncodeToString(host.Marshal())
userReq, err := json.Marshal(SignSSHRequest{
userReq, err := json.Marshal(SSHSignRequest{
PublicKey: user.Key.Marshal(),
OTT: "ott",
})
assert.FatalError(t, err)
hostReq, err := json.Marshal(SignSSHRequest{
hostReq, err := json.Marshal(SSHSignRequest{
PublicKey: host.Key.Marshal(),
OTT: "ott",
})
assert.FatalError(t, err)
userAddReq, err := json.Marshal(SignSSHRequest{
userAddReq, err := json.Marshal(SSHSignRequest{
PublicKey: user.Key.Marshal(),
OTT: "ott",
AddUserPublicKey: user.Key.Marshal(),
@ -299,7 +299,7 @@ func Test_caHandler_SignSSH(t *testing.T) {
req := httptest.NewRequest("POST", "http://example.com/ssh/sign", bytes.NewReader(tt.req))
w := httptest.NewRecorder()
h.SignSSH(logging.NewResponseLogger(w), req)
h.SSHSign(logging.NewResponseLogger(w), req)
res := w.Result()
if res.StatusCode != tt.statusCode {
@ -320,7 +320,7 @@ func Test_caHandler_SignSSH(t *testing.T) {
}
}
func Test_caHandler_SSHKeys(t *testing.T) {
func Test_caHandler_SSHRoots(t *testing.T) {
user, err := ssh.NewPublicKey(sshUserKey.Public())
assert.FatalError(t, err)
userB64 := base64.StdEncoding.EncodeToString(user.Marshal())
@ -336,22 +336,23 @@ func Test_caHandler_SSHKeys(t *testing.T) {
body []byte
statusCode int
}{
{"ok", &authority.SSHKeys{HostKey: host, UserKey: user}, nil, []byte(fmt.Sprintf(`{"userKey":"%s","hostKey":"%s"}`, userB64, hostB64)), http.StatusOK},
{"user", &authority.SSHKeys{UserKey: user}, nil, []byte(fmt.Sprintf(`{"userKey":"%s"}`, userB64)), http.StatusOK},
{"host", &authority.SSHKeys{HostKey: host}, nil, []byte(fmt.Sprintf(`{"hostKey":"%s"}`, hostB64)), http.StatusOK},
{"error", nil, fmt.Errorf("an error"), nil, http.StatusNotFound},
{"ok", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}, UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":["%s"],"hostKey":["%s"]}`, userB64, hostB64)), http.StatusOK},
{"user", &authority.SSHKeys{UserKeys: []ssh.PublicKey{user}}, nil, []byte(fmt.Sprintf(`{"userKey":["%s"]}`, userB64)), http.StatusOK},
{"host", &authority.SSHKeys{HostKeys: []ssh.PublicKey{host}}, nil, []byte(fmt.Sprintf(`{"hostKey":["%s"]}`, hostB64)), http.StatusOK},
{"empty", &authority.SSHKeys{}, nil, nil, http.StatusNotFound},
{"error", nil, fmt.Errorf("an error"), nil, http.StatusInternalServerError},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := New(&mockAuthority{
getSSHKeys: func() (*authority.SSHKeys, error) {
getSSHRoots: func() (*authority.SSHKeys, error) {
return tt.keys, tt.keysErr
},
}).(*caHandler)
req := httptest.NewRequest("GET", "http://example.com/ssh/keys", http.NoBody)
w := httptest.NewRecorder()
h.SSHKeys(logging.NewResponseLogger(w), req)
h.SSHRoots(logging.NewResponseLogger(w), req)
res := w.Result()
if res.StatusCode != tt.statusCode {

View file

@ -87,16 +87,16 @@ type SSHKeys struct {
HostKeys []ssh.PublicKey
}
// GetSSHKeys returns the SSH User and Host public keys.
func (a *Authority) GetSSHKeys() (*SSHKeys, error) {
// GetSSHRoots returns the SSH User and Host public keys.
func (a *Authority) GetSSHRoots() (*SSHKeys, error) {
return &SSHKeys{
HostKeys: a.sshCAHostCerts,
UserKeys: a.sshCAUserCerts,
}, nil
}
// GetSSHFederatedKeys returns the public keys for federated SSH signers.
func (a *Authority) GetSSHFederatedKeys() (*SSHKeys, error) {
// GetSSHFederation returns the public keys for federated SSH signers.
func (a *Authority) GetSSHFederation() (*SSHKeys, error) {
return &SSHKeys{
HostKeys: a.sshCAHostFederatedCerts,
UserKeys: a.sshCAUserFederatedCerts,

View file

@ -373,28 +373,6 @@ func (c *Client) Sign(req *api.SignRequest) (*api.SignResponse, error) {
return &sign, nil
}
// SignSSH performs the SSH certificate sign request to the CA and returns the
// api.SignSSHResponse struct.
func (c *Client) SignSSH(req *api.SignSSHRequest) (*api.SignSSHResponse, error) {
body, err := json.Marshal(req)
if err != nil {
return nil, errors.Wrap(err, "error marshaling request")
}
u := c.endpoint.ResolveReference(&url.URL{Path: "/ssh/sign"})
resp, err := c.client.Post(u.String(), "application/json", bytes.NewReader(body))
if err != nil {
return nil, errors.Wrapf(err, "client POST %s failed", u)
}
if resp.StatusCode >= 400 {
return nil, readError(resp.Body)
}
var sign api.SignSSHResponse
if err := readJSON(resp.Body, &sign); err != nil {
return nil, errors.Wrapf(err, "error reading %s", u)
}
return &sign, nil
}
// Renew performs the renew request to the CA and returns the api.SignResponse
// struct.
func (c *Client) Renew(tr http.RoundTripper) (*api.SignResponse, error) {
@ -527,10 +505,32 @@ func (c *Client) Federation() (*api.FederationResponse, error) {
return &federation, nil
}
// SSHKeys performs the get /ssh/keys request to the CA and returns the
// api.SSHKeysResponse struct.
func (c *Client) SSHKeys() (*api.SSHKeysResponse, error) {
u := c.endpoint.ResolveReference(&url.URL{Path: "/ssh/keys"})
// SSHSign performs the POST /ssh/sign request to the CA and returns the
// api.SSHSignResponse struct.
func (c *Client) SSHSign(req *api.SSHSignRequest) (*api.SSHSignResponse, error) {
body, err := json.Marshal(req)
if err != nil {
return nil, errors.Wrap(err, "error marshaling request")
}
u := c.endpoint.ResolveReference(&url.URL{Path: "/ssh/sign"})
resp, err := c.client.Post(u.String(), "application/json", bytes.NewReader(body))
if err != nil {
return nil, errors.Wrapf(err, "client POST %s failed", u)
}
if resp.StatusCode >= 400 {
return nil, readError(resp.Body)
}
var sign api.SSHSignResponse
if err := readJSON(resp.Body, &sign); err != nil {
return nil, errors.Wrapf(err, "error reading %s", u)
}
return &sign, nil
}
// SSHRoots performs the GET /ssh/roots request to the CA and returns the
// api.SSHRootsResponse struct.
func (c *Client) SSHRoots() (*api.SSHRootsResponse, error) {
u := c.endpoint.ResolveReference(&url.URL{Path: "/ssh/roots"})
resp, err := c.client.Get(u.String())
if err != nil {
return nil, errors.Wrapf(err, "client GET %s failed", u)
@ -538,7 +538,7 @@ func (c *Client) SSHKeys() (*api.SSHKeysResponse, error) {
if resp.StatusCode >= 400 {
return nil, readError(resp.Body)
}
var keys api.SSHKeysResponse
var keys api.SSHRootsResponse
if err := readJSON(resp.Body, &keys); err != nil {
return nil, errors.Wrapf(err, "error reading %s", u)
}
@ -546,8 +546,8 @@ func (c *Client) SSHKeys() (*api.SSHKeysResponse, error) {
}
// SSHFederation performs the get /ssh/federation request to the CA and returns
// the api.SSHKeysResponse struct.
func (c *Client) SSHFederation() (*api.SSHKeysResponse, error) {
// the api.SSHRootsResponse struct.
func (c *Client) SSHFederation() (*api.SSHRootsResponse, error) {
u := c.endpoint.ResolveReference(&url.URL{Path: "/ssh/federation"})
resp, err := c.client.Get(u.String())
if err != nil {
@ -556,15 +556,15 @@ func (c *Client) SSHFederation() (*api.SSHKeysResponse, error) {
if resp.StatusCode >= 400 {
return nil, readError(resp.Body)
}
var keys api.SSHKeysResponse
var keys api.SSHRootsResponse
if err := readJSON(resp.Body, &keys); err != nil {
return nil, errors.Wrapf(err, "error reading %s", u)
}
return &keys, nil
}
// SSHConfig performs the POST request to the CA to get the ssh configuration
// templates.
// SSHConfig performs the POST /ssh/config request to the CA to get the ssh
// configuration templates.
func (c *Client) SSHConfig(req *api.SSHConfigRequest) (*api.SSHConfigResponse, error) {
body, err := json.Marshal(req)
if err != nil {

View file

@ -722,15 +722,15 @@ func TestClient_Federation(t *testing.T) {
}
}
func TestClient_SSHKeys(t *testing.T) {
func TestClient_SSHRoots(t *testing.T) {
key, err := ssh.NewPublicKey(mustKey().Public())
if err != nil {
t.Fatal(err)
}
ok := &api.SSHKeysResponse{
HostKey: &api.SSHPublicKey{PublicKey: key},
UserKey: &api.SSHPublicKey{PublicKey: key},
ok := &api.SSHRootsResponse{
HostKeys: []api.SSHPublicKey{{PublicKey: key}},
UserKeys: []api.SSHPublicKey{{PublicKey: key}},
}
notFound := api.NotFound(fmt.Errorf("Not Found"))
@ -759,7 +759,7 @@ func TestClient_SSHKeys(t *testing.T) {
api.JSONStatus(w, tt.response, tt.responseCode)
})
got, err := c.SSHKeys()
got, err := c.SSHRoots()
if (err != nil) != tt.wantErr {
fmt.Printf("%+v", err)
t.Errorf("Client.SSHKeys() error = %v, wantErr %v", err, tt.wantErr)