diff --git a/http/sys_seal_test.go b/http/sys_seal_test.go index fa45dd9b9..bef331023 100644 --- a/http/sys_seal_test.go +++ b/http/sys_seal_test.go @@ -47,10 +47,10 @@ func TestSysSealStatus_uninit(t *testing.T) { } func TestSysSeal(t *testing.T) { - core := vault.TestCore(t) - vault.TestCoreInit(t, core) + core, _, token := vault.TestCoreUnsealed(t) ln, addr := TestServer(t, core) defer ln.Close() + TestServerAuth(t, addr, token) resp := testHttpPut(t, addr+"/v1/sys/seal", nil) testResponseStatus(t, resp, 204) diff --git a/vault/core.go b/vault/core.go index cfcf3e29a..31bab9d6d 100644 --- a/vault/core.go +++ b/vault/core.go @@ -225,38 +225,21 @@ func (c *Core) HandleRequest(req *logical.Request) (*logical.Response, error) { } func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) { - // Ensure there is a client token - if req.ClientToken == "" { - return logical.ErrorResponse("missing client token"), logical.ErrInvalidRequest - } - - // Resolve the token policy - te, err := c.tokenStore.Lookup(req.ClientToken) + // Validate the token + err := c.checkToken( + req.Operation, req.Path, req.ClientToken, c.router.RootPath(req.Path)) if err != nil { - c.logger.Printf("[ERR] core: failed to lookup token: %v", err) - return nil, ErrInternalError - } + // If it is an internal error we return that, otherwise we + // return invalid request so that the status codes can be correct + errType := logical.ErrInvalidRequest + switch err { + case ErrInternalError: + fallthrough + case logical.ErrPermissionDenied: + errType = err + } - // Ensure the token is valid - if te == nil { - return logical.ErrorResponse("invalid client token"), logical.ErrInvalidRequest - } - - // Construct the corresponding ACL object - acl, err := c.policy.ACL(te.Policies...) - if err != nil { - c.logger.Printf("[ERR] core: failed to construct ACL: %v", err) - return nil, ErrInternalError - } - - // Check if this is a root protected path - if c.router.RootPath(req.Path) && !acl.RootPrivilege(req.Path) { - return nil, logical.ErrPermissionDenied - } - - // Check the standard non-root ACLs - if !acl.AllowOperation(req.Operation, req.Path) { - return nil, logical.ErrPermissionDenied + return logical.ErrorResponse(err.Error()), errType } // Route the request @@ -321,6 +304,45 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, erro return resp, err } +func (c *Core) checkToken( + op logical.Operation, path string, token string, root bool) error { + // Ensure there is a client token + if token == "" { + return fmt.Errorf("missing client token") + } + + // Resolve the token policy + te, err := c.tokenStore.Lookup(token) + if err != nil { + c.logger.Printf("[ERR] core: failed to lookup token: %v", err) + return ErrInternalError + } + + // Ensure the token is valid + if te == nil { + return fmt.Errorf("invalid client token") + } + + // Construct the corresponding ACL object + acl, err := c.policy.ACL(te.Policies...) + if err != nil { + c.logger.Printf("[ERR] core: failed to construct ACL: %v", err) + return ErrInternalError + } + + // Check if this is a root protected path + if root && !acl.RootPrivilege(path) { + return logical.ErrPermissionDenied + } + + // Check the standard non-root ACLs + if !acl.AllowOperation(op, path) { + return logical.ErrPermissionDenied + } + + return nil +} + // Initialized checks if the Vault is already initialized func (c *Core) Initialized() (bool, error) { // Check the barrier first @@ -586,12 +608,23 @@ func (c *Core) Unseal(key []byte) (bool, error) { // Seal is used to re-seal the Vault. This requires the Vault to // be unsealed again to perform any further operations. -func (c *Core) Seal() error { +func (c *Core) Seal(token string) error { c.stateLock.Lock() defer c.stateLock.Unlock() if c.sealed { return nil } + + // Validate the token is a root token + err := c.checkToken( + logical.WriteOperation, + "sys/seal", + token, + true) + if err != nil { + return err + } + c.sealed = true // Do pre-seal teardown diff --git a/vault/core_test.go b/vault/core_test.go index 6d1089a33..7f1c5d2a0 100644 --- a/vault/core_test.go +++ b/vault/core_test.go @@ -202,13 +202,13 @@ func TestCore_Unseal_MultiShare(t *testing.T) { t.Fatalf("should not be sealed") } - err = c.Seal() + err = c.Seal(res.RootToken) if err != nil { t.Fatalf("err: %v", err) } // Ignore redundant - err = c.Seal() + err = c.Seal(res.RootToken) if err != nil { t.Fatalf("err: %v", err) } @@ -312,8 +312,8 @@ func TestCore_Route_Sealed(t *testing.T) { // Attempt to unseal after doing a first seal func TestCore_SealUnseal(t *testing.T) { - c, key, _ := TestCoreUnsealed(t) - if err := c.Seal(); err != nil { + c, key, root := TestCoreUnsealed(t) + if err := c.Seal(root); err != nil { t.Fatalf("err: %v", err) } if unseal, err := c.Unseal(key); err != nil || !unseal { @@ -416,10 +416,7 @@ func TestCore_HandleRequest_RootPath(t *testing.T) { } resp, err := c.HandleRequest(req) if err != logical.ErrPermissionDenied { - t.Fatalf("err: %v", err) - } - if resp != nil { - t.Fatalf("bad: %#v", resp) + t.Fatalf("err: %v, resp: %v", err, resp) } } @@ -476,10 +473,7 @@ func TestCore_HandleRequest_PermissionDenied(t *testing.T) { } resp, err := c.HandleRequest(req) if err != logical.ErrPermissionDenied { - t.Fatalf("err: %v", err) - } - if resp != nil { - t.Fatalf("bad: %#v", resp) + t.Fatalf("err: %v, resp: %v", err, resp) } } diff --git a/vault/logical_system.go b/vault/logical_system.go index 8b644953a..aaeb57e67 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -20,7 +20,6 @@ func NewSystemBackend(core *Core) logical.Backend { "revoke-prefix/*", "policy", "policy/*", - "seal", }, }, @@ -216,17 +215,6 @@ func NewSystemBackend(core *Core) logical.Backend { HelpSynopsis: strings.TrimSpace(sysHelp["policy"][0]), HelpDescription: strings.TrimSpace(sysHelp["policy"][1]), }, - - &framework.Path{ - Pattern: "seal$", - - Callbacks: map[logical.Operation]framework.OperationFunc{ - logical.WriteOperation: b.handleSeal, - }, - - HelpSynopsis: strings.TrimSpace(sysHelp["seal"][0]), - HelpDescription: strings.TrimSpace(sysHelp["seal"][1]), - }, }, } } @@ -238,17 +226,6 @@ type SystemBackend struct { Core *Core } -// handleSeal is used to mount a new path -func (b *SystemBackend) handleSeal( - req *logical.Request, data *framework.FieldData) (*logical.Response, error) { - // Attempt seal - if err := b.Core.Seal(); err != nil { - return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest - } - - return nil, nil -} - // handleMountTable handles the "mounts" endpoint to provide the mount table func (b *SystemBackend) handleMountTable( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { diff --git a/vault/logical_system_test.go b/vault/logical_system_test.go index 4ff4bbfae..e5b88b2b0 100644 --- a/vault/logical_system_test.go +++ b/vault/logical_system_test.go @@ -15,7 +15,6 @@ func TestSystemBackend_RootPaths(t *testing.T) { "revoke-prefix/*", "policy", "policy/*", - "seal", } b := testSystemBackend(t) @@ -25,22 +24,6 @@ func TestSystemBackend_RootPaths(t *testing.T) { } } -func TestSystemBackend_seal(t *testing.T) { - core, b, _ := testCoreSystemBackend(t) - req := logical.TestRequest(t, logical.WriteOperation, "seal") - _, err := b.HandleRequest(req) - if err != nil { - t.Fatalf("err: %v", err) - } - - sealed, err := core.Sealed() - if err != nil { - t.Fatalf("err: %v", err) - } - if !sealed { - t.Fatal("should be sealed") - } -} func TestSystemBackend_mounts(t *testing.T) { b := testSystemBackend(t) req := logical.TestRequest(t, logical.ReadOperation, "mounts")