Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make auth/token/revoke-accessor idempotent #13661

Merged
merged 3 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/13661.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
```release-note:improvement
auth/token: The `auth/token/revoke-accessor` endpoint is now idempotent and will
not error out if the token has already been revoked.
```
3 changes: 3 additions & 0 deletions vault/logical_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,9 @@ func (b *SystemBackend) handleCapabilitiesAccessor(ctx context.Context, req *log
if err != nil {
return nil, err
}
if aEntry == nil {
return nil, &logical.StatusBadRequest{Err: "invalid accessor"}
}

d.Raw["token"] = aEntry.TokenID
return b.handleCapabilities(ctx, req, d)
Expand Down
33 changes: 25 additions & 8 deletions vault/token_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,10 @@ func (ts *TokenStore) tokenStoreAccessorList(ctx context.Context, req *logical.R
resp.AddWarning(fmt.Sprintf("Found an accessor entry that could not be successfully decoded; associated error is %q", err.Error()))
continue
}
if aEntry == nil {
resp.AddWarning("Found an accessor entry that could not be successfully decoded: invalid accessor")
remilapeyre marked this conversation as resolved.
Show resolved Hide resolved
continue
}

if aEntry.TokenID == "" {
resp.AddWarning(fmt.Sprintf("Found an accessor entry missing a token: %v", aEntry.AccessorID))
Expand Down Expand Up @@ -1741,12 +1745,12 @@ func (ts *TokenStore) handleCreateAgainstRole(ctx context.Context, req *logical.
return ts.handleCreateCommon(ctx, req, d, false, roleEntry)
}

func (ts *TokenStore) lookupByAccessor(ctx context.Context, id string, salted, tainted bool) (accessorEntry, error) {
func (ts *TokenStore) lookupByAccessor(ctx context.Context, id string, salted, tainted bool) (*accessorEntry, error) {
var aEntry accessorEntry

ns, err := namespace.FromContext(ctx)
if err != nil {
return aEntry, err
return nil, err
}

lookupID := id
Expand All @@ -1755,7 +1759,7 @@ func (ts *TokenStore) lookupByAccessor(ctx context.Context, id string, salted, t
if nsID != "" {
accessorNS, err := NamespaceByID(ctx, nsID, ts.core)
if err != nil {
return aEntry, err
return nil, err
}
if accessorNS != nil {
if accessorNS.ID != ns.ID {
Expand All @@ -1773,24 +1777,24 @@ func (ts *TokenStore) lookupByAccessor(ctx context.Context, id string, salted, t

lookupID, err = ts.SaltID(ctx, id)
if err != nil {
return aEntry, err
return nil, err
}
}

entry, err := ts.accessorView(ns).Get(ctx, lookupID)
if err != nil {
return aEntry, fmt.Errorf("failed to read index using accessor: %w", err)
return nil, fmt.Errorf("failed to read index using accessor: %w", err)
}
if entry == nil {
return aEntry, &logical.StatusBadRequest{Err: "invalid accessor"}
return nil, nil
}

err = jsonutil.DecodeJSON(entry.Value, &aEntry)
// If we hit an error, assume it's a pre-struct straight token ID
if err != nil {
te, err := ts.lookupInternal(ctx, string(entry.Value), false, tainted)
if err != nil {
return accessorEntry{}, fmt.Errorf("failed to look up token using accessor index: %w", err)
return nil, fmt.Errorf("failed to look up token using accessor index: %w", err)
}
// It's hard to reason about what to do here if te is nil -- it may be
// that the token was revoked async, or that it's an old accessor index
Expand All @@ -1808,7 +1812,7 @@ func (ts *TokenStore) lookupByAccessor(ctx context.Context, id string, salted, t
aEntry.NamespaceID = namespace.RootNamespaceID
}

return aEntry, nil
return &aEntry, nil
}

// handleTidy handles the cleaning up of leaked accessor storage entries and
Expand Down Expand Up @@ -1959,6 +1963,10 @@ func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data
tidyErrors = multierror.Append(tidyErrors, fmt.Errorf("failed to read the accessor index: %w", err))
continue
}
if accessorEntry == nil {
tidyErrors = multierror.Append(tidyErrors, fmt.Errorf("failed to read the accessor index: invalid accessor"))
continue
}

// A valid accessor storage entry should always have a token ID
// in it. If not, it is an invalid accessor entry and needs to
Expand Down Expand Up @@ -2098,6 +2106,9 @@ func (ts *TokenStore) handleUpdateLookupAccessor(ctx context.Context, req *logic
if err != nil {
return nil, err
}
if aEntry == nil {
return nil, &logical.StatusBadRequest{Err: "invalid accessor"}
}

// Prepare the field data required for a lookup call
d := &framework.FieldData{
Expand Down Expand Up @@ -2140,6 +2151,9 @@ func (ts *TokenStore) handleUpdateRenewAccessor(ctx context.Context, req *logica
if err != nil {
return nil, err
}
if aEntry == nil {
return nil, &logical.StatusBadRequest{Err: "invalid accessor"}
}

// Prepare the field data required for a lookup call
d := &framework.FieldData{
Expand Down Expand Up @@ -2190,6 +2204,9 @@ func (ts *TokenStore) handleUpdateRevokeAccessor(ctx context.Context, req *logic
if err != nil {
return nil, err
}
if aEntry == nil {
remilapeyre marked this conversation as resolved.
Show resolved Hide resolved
return nil, nil
}

te, err := ts.Lookup(ctx, aEntry.TokenID)
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions vault/token_store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,13 @@ func TestTokenStore_HandleRequest_Renew_Revoke_Accessor(t *testing.T) {
t.Fatalf("err: %s", err)
}

// Revoking the token using the accessor should be idempotent since
// auth/token/revoke is
_, err = ts.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %s", err)
}

time.Sleep(200 * time.Millisecond)

out, err = ts.Lookup(namespace.RootContext(nil), "tokenid")
Expand Down