From 6ccded7a2fb6405aad2464f541f6490bf440a94d Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Tue, 3 Nov 2015 15:10:46 -0500 Subject: [PATCH] Add ability to create orphan tokens from the API --- CHANGELOG.md | 1 + vault/token_store.go | 33 ++++++++++++++++++++++++++++++++- vault/token_store_test.go | 21 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 234cc67c9..c287a27cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ generate them, leading to client errors. could fail to revert to a clean state [GH-733] * everywhere: Don't use http.DefaultClient, as it shares state implicitly and is a source of hard-to-track-down bugs [GH-700] + * credential/token: Allow creating orphan tokens via an API path [GH-748] * secret/generic: Validate given duration at write time, not just read time; if stored durations are not parseable, return a warning and the default duration rather than an error [GH-718] diff --git a/vault/token_store.go b/vault/token_store.go index e3ad9ea08..638990988 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -89,6 +89,17 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error) }, Paths: []*framework.Path{ + &framework.Path{ + Pattern: "create-orphan$", + + Callbacks: map[logical.Operation]framework.OperationFunc{ + logical.WriteOperation: t.handleCreateOrphan, + }, + + HelpSynopsis: strings.TrimSpace(tokenCreateOrphanHelp), + HelpDescription: strings.TrimSpace(tokenCreateOrphanHelp), + }, + &framework.Path{ Pattern: "create$", @@ -501,9 +512,23 @@ func (ts *TokenStore) revokeTreeSalted(saltedId string) error { return nil } -// handleCreate handles the auth/token/create path for creation of new tokens +// handleCreate handles the auth/token/create path for creation of new orphan +// tokens +func (ts *TokenStore) handleCreateOrphan( + req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + return ts.handleCreateCommon(req, d, true) +} + +// handleCreate handles the auth/token/create path for creation of new non-orphan +// tokens func (ts *TokenStore) handleCreate( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { + return ts.handleCreateCommon(req, d, false) +} + +// handleCreateCommon handles the auth/token/create path for creation of new tokens +func (ts *TokenStore) handleCreateCommon( + req *logical.Request, d *framework.FieldData, orphan bool) (*logical.Response, error) { // Read the parent policy parent, err := ts.Lookup(req.ClientToken) if err != nil || parent == nil { @@ -586,6 +611,11 @@ func (ts *TokenStore) handleCreate( } te.Parent = "" + } else { + // This comes from create-orphan, which can be properly ACLd + if orphan { + te.Parent = "" + } } // Parse the TTL/lease if any @@ -839,6 +869,7 @@ Client tokens are used to identify a client and to allow Vault to associate poli which are enforced on every request. This backend also allows for generating sub-tokens as well as revocation of tokens. The tokens are renewable if associated with a lease.` tokenCreateHelp = `The token create path is used to create new tokens.` + tokenCreateOrphanHelp = `The token create path is used to create new orphan tokens.` tokenLookupHelp = `This endpoint will lookup a token and its properties.` tokenRevokeHelp = `This endpoint will delete the given token and all of its child tokens.` tokenRevokeSelfHelp = `This endpoint will delete the token used to call it and all of its child tokens.` diff --git a/vault/token_store_test.go b/vault/token_store_test.go index f4b1388af..9682f30e9 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -662,6 +662,27 @@ func TestTokenStore_HandleRequest_CreateToken_Root_NoParent(t *testing.T) { } } +func TestTokenStore_HandleRequest_CreateToken_PathBased_NoParent(t *testing.T) { + _, ts, root := mockTokenStore(t) + + req := logical.TestRequest(t, logical.WriteOperation, "create-orphan") + req.ClientToken = root + req.Data["policies"] = []string{"foo"} + + resp, err := ts.HandleRequest(req) + if err != nil { + t.Fatalf("err: %v %v", err, resp) + } + if resp.Auth.ClientToken == "" { + t.Fatalf("bad: %#v", resp) + } + + out, _ := ts.Lookup(resp.Auth.ClientToken) + if out.Parent != "" { + t.Fatalf("bad: %#v", out) + } +} + func TestTokenStore_HandleRequest_CreateToken_Metadata(t *testing.T) { _, ts, root := mockTokenStore(t)