vault: adding auth/token/revoke/ and auth/token/revoke-orphan/

This commit is contained in:
Armon Dadgar 2015-03-24 15:30:09 -07:00
parent 26f05f7a20
commit 4a4d1d3e45
2 changed files with 134 additions and 3 deletions

View File

@ -300,6 +300,8 @@ func (ts *TokenStore) HandleRequest(req *logical.Request) (*logical.Response, er
switch {
case req.Path == "create":
return ts.handleCreate(req)
case strings.HasPrefix(req.Path, "revoke/"):
return ts.handleRevokeTree(req)
case strings.HasPrefix(req.Path, "revoke-orphan/"):
return ts.handleRevokeOrphan(req)
case req.Path == "":
@ -426,6 +428,32 @@ func (ts *TokenStore) handleCreate(req *logical.Request) (*logical.Response, err
return resp, nil
}
// handleRevokeTree handles the auth/token/revoke/id path for revocation of tokens
// in a way that revokes all child tokens. Normally, using sys/revoke/vaultID will revoke
// the token and all children anyways, but that is only available when there is a lease.
func (ts *TokenStore) handleRevokeTree(req *logical.Request) (*logical.Response, error) {
// Validate the operation
switch req.Operation {
case logical.WriteOperation:
case logical.HelpOperation:
return logical.HelpResponse(tokenRevokeHelp, nil), nil
default:
return nil, logical.ErrUnsupportedOperation
}
// Parse the id
id := strings.TrimPrefix(req.Path, "revoke/")
if id == "" {
return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest
}
// Revoke the token and its children
if err := ts.RevokeTree(id); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
return nil, nil
}
// handleRevokeOrphan handles the auth/token/revoke-orphan/id path for revocation of tokens
// in a way that leaves child tokens orphaned. Normally, using sys/revoke/vaultID will revoke
// the token and all children.
@ -433,10 +461,22 @@ func (ts *TokenStore) handleRevokeOrphan(req *logical.Request) (*logical.Respons
// Validate the operation
switch req.Operation {
case logical.WriteOperation:
case logical.HelpOperation:
return logical.HelpResponse(tokenRevokeOrphanHelp, nil), nil
default:
return nil, logical.ErrUnsupportedOperation
}
// Parse the id
id := strings.TrimPrefix(req.Path, "revoke-orphan/")
if id == "" {
return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest
}
// Revoke and orphan
if err := ts.Revoke(id); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
return nil, nil
}
@ -445,6 +485,7 @@ const (
Client tokens are used to identify a client and to allow Vault to associate policies and ACLs
which are enforced on every request. This backend also allows for generating sub-tokens as well
as revocation of tokens.`
tokenCreateHelp = `The token create path is used to create new tokens.`
tokenCreateHelp = `The token create path is used to create new tokens.`
tokenRevokeHelp = `This endpoint will delete the token and all of its child tokens.`
tokenRevokeOrphanHelp = `This endpoint will delete the token and orphan its child tokens.`
)

View File

@ -452,6 +452,96 @@ func TestTokenStore_HandleRequest_CreateToken_Lease(t *testing.T) {
}
}
func TestTokenStore_HandleRequest_Revoke_MissingToken(t *testing.T) {
_, ts, _ := mockTokenStore(t)
req := logical.TestRequest(t, logical.WriteOperation, "revoke/")
resp, err := ts.HandleRequest(req)
if err != logical.ErrInvalidRequest {
t.Fatalf("err: %v %v", err, resp)
}
if resp.Data["error"] != "missing token ID" {
t.Fatalf("bad: %#v", resp)
}
}
func TestTokenStore_HandleRequest_Revoke(t *testing.T) {
_, ts, root := mockTokenStore(t)
testMakeToken(t, ts, root, "child", []string{"root", "foo"})
testMakeToken(t, ts, "child", "sub-child", []string{"foo"})
req := logical.TestRequest(t, logical.WriteOperation, "revoke/child")
resp, err := ts.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v %v", err, resp)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
out, err := ts.Lookup("child")
if err != nil {
t.Fatalf("err: %v", err)
}
if out != nil {
t.Fatalf("bad: %v", out)
}
// Sub-child should not exist
out, err = ts.Lookup("sub-child")
if err != nil {
t.Fatalf("err: %v", err)
}
if out != nil {
t.Fatalf("bad: %v", out)
}
}
func TestTokenStore_HandleRequest_RevokeOrphan_MissingToken(t *testing.T) {
_, ts, _ := mockTokenStore(t)
req := logical.TestRequest(t, logical.WriteOperation, "revoke-orphan/")
resp, err := ts.HandleRequest(req)
if err != logical.ErrInvalidRequest {
t.Fatalf("err: %v %v", err, resp)
}
if resp.Data["error"] != "missing token ID" {
t.Fatalf("bad: %#v", resp)
}
}
func TestTokenStore_HandleRequest_RevokeOrphan(t *testing.T) {
_, ts, root := mockTokenStore(t)
testMakeToken(t, ts, root, "child", []string{"root", "foo"})
testMakeToken(t, ts, "child", "sub-child", []string{"foo"})
req := logical.TestRequest(t, logical.WriteOperation, "revoke-orphan/child")
resp, err := ts.HandleRequest(req)
if err != nil {
t.Fatalf("err: %v %v", err, resp)
}
if resp != nil {
t.Fatalf("bad: %#v", resp)
}
out, err := ts.Lookup("child")
if err != nil {
t.Fatalf("err: %v", err)
}
if out != nil {
t.Fatalf("bad: %v", out)
}
// Sub-child should exist!
out, err = ts.Lookup("sub-child")
if err != nil {
t.Fatalf("err: %v", err)
}
if out == nil {
t.Fatalf("bad: %v", out)
}
}
func testMakeToken(t *testing.T, ts *TokenStore, root, client string, policy []string) {
req := logical.TestRequest(t, logical.WriteOperation, "create")
req.ClientToken = root
@ -462,7 +552,7 @@ func testMakeToken(t *testing.T, ts *TokenStore, root, client string, policy []s
if err != nil {
t.Fatalf("err: %v %v", err, resp)
}
if resp.Data[clientTokenKey] != "client" {
if resp.Data[clientTokenKey] != client {
t.Fatalf("bad: %#v", resp)
}
}