-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Revoke multiple tokens/accessors #2922
Changes from 6 commits
6d36c84
57f22d3
22811a9
bb88dae
fc1c616
4d33f2e
6fa7596
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -335,12 +335,12 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error) | |
|
||
Fields: map[string]*framework.FieldSchema{ | ||
"urlaccessor": &framework.FieldSchema{ | ||
Type: framework.TypeString, | ||
Description: "Accessor of the token (URL parameter)", | ||
Type: framework.TypeCommaStringSlice, | ||
Description: "Accessor(s) of the token (URL parameter)", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The URL parameter can't be used in this way, and it's also deprecated. Just the request body is sufficient. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
}, | ||
"accessor": &framework.FieldSchema{ | ||
Type: framework.TypeString, | ||
Description: "Accessor of the token (request body)", | ||
Type: framework.TypeCommaStringSlice, | ||
Description: "Accessor(s) of the token (request body)", | ||
}, | ||
}, | ||
|
||
|
@@ -368,12 +368,12 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error) | |
|
||
Fields: map[string]*framework.FieldSchema{ | ||
"urltoken": &framework.FieldSchema{ | ||
Type: framework.TypeString, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
Description: "Token to revoke (URL parameter)", | ||
Type: framework.TypeCommaStringSlice, | ||
Description: "Token(s) to revoke (URL parameter)", | ||
}, | ||
"token": &framework.FieldSchema{ | ||
Type: framework.TypeString, | ||
Description: "Token to revoke (request body)", | ||
Type: framework.TypeCommaStringSlice, | ||
Description: "Token(s) to revoke (request body)", | ||
}, | ||
}, | ||
|
||
|
@@ -1039,6 +1039,20 @@ func (ts *TokenStore) RevokeTree(id string) error { | |
return nil | ||
} | ||
|
||
// RevokeTrees is used to invalide multiple tokens and all | ||
// child tokens. | ||
func (ts *TokenStore) RevokeTrees(ids []string) []error { | ||
defer metrics.MeasureSince([]string{"token", "revoke-trees"}, time.Now()) | ||
|
||
errs := make([]error, len(ids)) | ||
|
||
for idx, id := range ids { | ||
errs[idx] = ts.RevokeTree(id) | ||
} | ||
|
||
return errs | ||
} | ||
|
||
// revokeTreeSalted is used to invalide a given token and all | ||
// child tokens using a saltedID. | ||
func (ts *TokenStore) revokeTreeSalted(saltedId string) error { | ||
|
@@ -1325,32 +1339,58 @@ func (ts *TokenStore) handleUpdateLookupAccessor(req *logical.Request, data *fra | |
// the token associated with the accessor | ||
func (ts *TokenStore) handleUpdateRevokeAccessor(req *logical.Request, data *framework.FieldData) (*logical.Response, error) { | ||
var urlaccessor bool | ||
accessor := data.Get("accessor").(string) | ||
if accessor == "" { | ||
accessor = data.Get("urlaccessor").(string) | ||
if accessor == "" { | ||
accessors := data.Get("accessor").([]string) | ||
|
||
if len(accessors) == 0 { | ||
accessors = data.Get("urlaccessor").([]string) | ||
if len(accessors) == 0 { | ||
return nil, &logical.StatusBadRequest{Err: "missing accessor"} | ||
} | ||
urlaccessor = true | ||
} | ||
|
||
aEntry, err := ts.lookupByAccessor(accessor, true) | ||
if err != nil { | ||
return nil, err | ||
errs := make([]error, len(accessors)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comments below about using |
||
tokens := make([]string, len(accessors)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This list may not be the length of the accessor list in the case of errors. I would just set it to length zero and append to the slice. |
||
|
||
for idx, accessor := range accessors { | ||
aEntry, err := ts.lookupByAccessor(accessor, true) | ||
if err != nil { | ||
errs[idx] = err | ||
tokens[idx] = "" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You will need to |
||
} | ||
|
||
tokens[idx] = aEntry.TokenID | ||
} | ||
|
||
// Revoke the token and its children | ||
if err := ts.RevokeTree(aEntry.TokenID); err != nil { | ||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest | ||
revokeErrors := ts.RevokeTrees(tokens) | ||
|
||
response := &logical.Response{} | ||
failedRevokes := make([]map[string]string, 0, len(revokeErrors)) | ||
|
||
for idx, revokeError := range revokeErrors { | ||
if errs[idx] == nil { | ||
errs[idx] = revokeError | ||
} | ||
|
||
if errs[idx] != nil { | ||
failedRevokes = append(failedRevokes, map[string]string{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I'm not sure what this should be, I'm sure that it should not be a string map. Possibly the return value should be a slice of the same size as the input with either nulls or error messages. There's no need to return the accessors if the ordering is the same. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I am also not sure about this part, if number of revoked accessors/tokens are small, thats fine, if we are going to revoke millions of tokens at once, response may contain huge unnecessary data millions of nulls or empty strings
How user will determine which accessors are failed, ordering is same, but not all accessors may fail? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When something returns multiple errors, we normally use hashicorp/go-multierror and I think it would work in this case. I think it would remove a lot of the backwards compatibility logic since it would just contain one error in the case of a single accessor. |
||
"accessor": accessors[idx], | ||
"error": errs[idx].Error(), | ||
}) | ||
} | ||
} | ||
|
||
if len(failedRevokes) > 0 { | ||
response.SetError(fmt.Errorf("contains failed revokes"), failedRevokes) | ||
} | ||
|
||
if urlaccessor { | ||
resp := &logical.Response{} | ||
resp.AddWarning(`Using an accessor in the path is unsafe as the accessor can be logged in many places. Please use POST or PUT with the accessor passed in via the "accessor" parameter.`) | ||
return resp, nil | ||
response.AddWarning(`Using an accessor in the path is unsafe as the accessor can be logged in many places. Please use POST or PUT with the accessor passed in via the "accessor" parameter.`) | ||
} else if len(failedRevokes) == 0 { | ||
return nil, nil | ||
} | ||
|
||
return nil, nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If only a single accessor is given, the previous return values should be retained. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
return response, nil | ||
} | ||
|
||
// handleCreate handles the auth/token/create path for creation of new orphan | ||
|
@@ -1793,27 +1833,41 @@ func (ts *TokenStore) handleRevokeSelf( | |
func (ts *TokenStore) handleRevokeTree( | ||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) { | ||
var urltoken bool | ||
id := data.Get("token").(string) | ||
if id == "" { | ||
id = data.Get("urltoken").(string) | ||
if id == "" { | ||
tokens := data.Get("token").([]string) | ||
|
||
if len(tokens) == 0 { | ||
tokens = data.Get("urltoken").([]string) | ||
if len(tokens) == 0 { | ||
return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest | ||
} | ||
urltoken = true | ||
} | ||
|
||
// Revoke the token and its children | ||
if err := ts.RevokeTree(id); err != nil { | ||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest | ||
revokeErrors := ts.RevokeTrees(tokens) | ||
|
||
response := &logical.Response{} | ||
failedRevokes := make([]map[string]string, 0, len(revokeErrors)) | ||
|
||
for idx, revokeError := range revokeErrors { | ||
if revokeError != nil { | ||
failedRevokes = append(failedRevokes, map[string]string{ | ||
"token": tokens[idx], | ||
"error": revokeError.Error(), | ||
}) | ||
} | ||
} | ||
|
||
if len(failedRevokes) > 0 { | ||
response.SetError(fmt.Errorf("contains failed revokes"), failedRevokes) | ||
} | ||
|
||
if urltoken { | ||
resp := &logical.Response{} | ||
resp.AddWarning(`Using a token in the path is unsafe as the token can be logged in many places. Please use POST or PUT with the token passed in via the "token" parameter.`) | ||
return resp, nil | ||
response.AddWarning(`Using a token in the path is unsafe as the token can be logged in many places. Please use POST or PUT with the token passed in via the "token" parameter.`) | ||
} else if len(failedRevokes) == 0 { | ||
return nil, nil | ||
} | ||
|
||
return nil, nil | ||
return response, nil | ||
} | ||
|
||
// handleRevokeOrphan handles the auth/token/revoke-orphan/id path for revocation of tokens | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we need this method on the response struct. I would much rather formatting of the errors being handled by the caller instead of trying to generalize it here.