From 811799637870e12f4bb03a5bcfa000975f981e3d Mon Sep 17 00:00:00 2001 From: vishalnayak Date: Tue, 8 Mar 2016 19:14:29 -0500 Subject: [PATCH] Implemented /sys/capabilities-accessor and a way for setting HTTP error code in all the responses --- http/handler.go | 20 +++++++++++----- http/sys_capabilities.go | 50 +++++++++++++++++++++++++++++++--------- vault/capabilities.go | 23 ++++++++++++++++++ 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/http/handler.go b/http/handler.go index 951d961fc..d77f602e1 100644 --- a/http/handler.go +++ b/http/handler.go @@ -35,6 +35,7 @@ func Handler(core *vault.Core) http.Handler { mux.Handle("/v1/sys/rekey/update", handleSysRekeyUpdate(core)) mux.Handle("/v1/sys/capabilities", handleSysCapabilities(core)) mux.Handle("/v1/sys/capabilities-self", handleSysCapabilities(core)) + mux.Handle("/v1/sys/capabilities-accessor", handleSysCapabilitiesAccessor(core)) mux.Handle("/v1/sys/", handleLogical(core, true)) mux.Handle("/v1/", handleLogical(core, false)) @@ -80,12 +81,7 @@ func request(core *vault.Core, w http.ResponseWriter, rawReq *http.Request, r *l return resp, false } if err != nil { - // Keep on adding error types here to set proper HTTP status code - if errwrap.ContainsType(err, new(vault.ErrUserInput)) { - respondError(w, http.StatusBadRequest, err) - } else { - respondError(w, http.StatusInternalServerError, err) - } + respondErrorStatus(w, err) return resp, false } @@ -145,6 +141,18 @@ func requestAuth(r *http.Request, req *logical.Request) *logical.Request { return req } +// Determines the type of the error being returned and sets the HTTP +// status code appropriately +func respondErrorStatus(w http.ResponseWriter, err error) { + status := http.StatusInternalServerError + switch { + // Keep adding more error types here to appropriate the status codes + case errwrap.ContainsType(err, new(vault.ErrUserInput)): + status = http.StatusBadRequest + } + respondError(w, status, err) +} + func respondError(w http.ResponseWriter, status int, err error) { // Adjust status code when sealed if err == vault.ErrSealed { diff --git a/http/sys_capabilities.go b/http/sys_capabilities.go index 48f41c778..701bad827 100644 --- a/http/sys_capabilities.go +++ b/http/sys_capabilities.go @@ -4,11 +4,40 @@ import ( "net/http" "strings" - "github.com/hashicorp/errwrap" "github.com/hashicorp/vault/logical" "github.com/hashicorp/vault/vault" ) +func handleSysCapabilitiesAccessor(core *vault.Core) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "PUT": + case "POST": + default: + respondError(w, http.StatusMethodNotAllowed, nil) + return + } + + // Parse the request if we can + var data capabilitiesAccessorRequest + if err := parseRequest(r, &data); err != nil { + respondError(w, http.StatusBadRequest, err) + return + } + + capabilities, err := core.CapabilitiesAccessor(data.AccessorID, data.Path) + if err != nil { + respondErrorStatus(w, err) + return + } + + respondOk(w, &capabilitiesResponse{ + Capabilities: capabilities, + }) + }) + +} + func handleSysCapabilities(core *vault.Core) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.Method { @@ -19,9 +48,6 @@ func handleSysCapabilities(core *vault.Core) http.Handler { return } - // Get the auth for the request so we can access the token directly - req := requestAuth(r, &logical.Request{}) - // Parse the request if we can var data capabilitiesRequest if err := parseRequest(r, &data); err != nil { @@ -30,18 +56,15 @@ func handleSysCapabilities(core *vault.Core) http.Handler { } if strings.HasPrefix(r.URL.Path, "/v1/sys/capabilities-self") { + // Get the auth for the request so we can access the token directly + req := requestAuth(r, &logical.Request{}) data.Token = req.ClientToken } capabilities, err := core.Capabilities(data.Token, data.Path) if err != nil { - if errwrap.ContainsType(err, new(vault.ErrUserInput)) { - respondError(w, http.StatusBadRequest, err) - return - } else { - respondError(w, http.StatusInternalServerError, err) - return - } + respondErrorStatus(w, err) + return } respondOk(w, &capabilitiesResponse{ @@ -59,3 +82,8 @@ type capabilitiesRequest struct { Token string `json:"token"` Path string `json:"path"` } + +type capabilitiesAccessorRequest struct { + AccessorID string `json:"accessor_id"` + Path string `json:"path"` +} diff --git a/vault/capabilities.go b/vault/capabilities.go index fb9c1ad93..39a30bd3d 100644 --- a/vault/capabilities.go +++ b/vault/capabilities.go @@ -12,6 +12,29 @@ func (e *ErrUserInput) Error() string { return e.Message } +// CapabilitiesAccessor is used to fetch the capabilities of the token associated with +// the token accessor an the given path +func (c *Core) CapabilitiesAccessor(accessorID, path string) ([]string, error) { + if path == "" { + return nil, &ErrUserInput{ + Message: "missing path", + } + } + + if accessorID == "" { + return nil, &ErrUserInput{ + Message: "missing accessor_id", + } + } + + token, err := c.tokenStore.lookupByAccessorID(accessorID) + if err != nil { + return nil, err + } + + return c.Capabilities(token, path) +} + // Capabilities is used to fetch the capabilities of the given token on the given path func (c *Core) Capabilities(token, path string) ([]string, error) { if path == "" {