Add possibility to decode generated encoded root token to api (#20595)

This commit is contained in:
l-with 2023-05-18 21:18:19 +02:00 committed by GitHub
parent f9fdac0345
commit d1d3d697da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 137 additions and 0 deletions

3
changelog/20595.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
core: Add possibility to decode a generated encoded root token via the rest API
```

View File

@ -44,6 +44,7 @@ import (
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/helper/pluginutil"
"github.com/hashicorp/vault/sdk/helper/roottoken"
"github.com/hashicorp/vault/sdk/helper/wrapping"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/version"
@ -150,6 +151,7 @@ func NewSystemBackend(core *Core, logger log.Logger) *SystemBackend {
"health",
"generate-root/attempt",
"generate-root/update",
"decode-token",
"rekey/init",
"rekey/update",
"rekey/verify",
@ -923,6 +925,24 @@ func (b *SystemBackend) handleRekeyDeleteRecovery(ctx context.Context, req *logi
return b.handleRekeyDelete(ctx, req, data, true)
}
func (b *SystemBackend) handleGenerateRootDecodeTokenUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
encodedToken := data.Get("encoded_token").(string)
otp := data.Get("otp").(string)
token, err := roottoken.DecodeToken(encodedToken, otp, len(otp))
if err != nil {
return nil, err
}
// Generate the response
resp := &logical.Response{
Data: map[string]interface{}{
"token": token,
},
}
return resp, nil
}
func (b *SystemBackend) mountInfo(ctx context.Context, entry *MountEntry) map[string]interface{} {
info := map[string]interface{}{
"type": entry.Type,

View File

@ -466,6 +466,32 @@ func (b *SystemBackend) configPaths() []*framework.Path {
HelpSynopsis: strings.TrimSpace(sysHelp["generate-root"][0]),
HelpDescription: strings.TrimSpace(sysHelp["generate-root"][1]),
},
{
Pattern: "decode-token$",
Fields: map[string]*framework.FieldSchema{
"encoded_token": {
Type: framework.TypeString,
Description: "Specifies the encoded token (result from generate-root).",
},
"otp": {
Type: framework.TypeString,
Description: "Specifies the otp code for decode.",
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleGenerateRootDecodeTokenUpdate,
DisplayAttrs: &framework.DisplayAttributes{
OperationVerb: "decode",
},
Summary: "Decodes the encoded token with the otp.",
Responses: map[int][]framework.Response{
http.StatusOK: {{Description: "OK"}},
},
},
},
},
{
Pattern: "health$",
Fields: map[string]*framework.FieldSchema{

View File

@ -2420,6 +2420,60 @@ func TestSystemBackend_enableAudit(t *testing.T) {
}
}
// TestSystemBackend_decodeToken ensures the correct decoding of the encoded token.
// It also ensures that the API fails if there is some payload missing.
func TestSystemBackend_decodeToken(t *testing.T) {
encodedToken := "Bxg9JQQqOCNKBRICNwMIRzo2J3cWCBRi"
otp := "3JhHkONiyiaNYj14nnD9xZQS"
tokenExpected := "4RUmoevJ3lsLni9sTXcNnRE1"
_, b, _ := testCoreSystemBackend(t)
req := logical.TestRequest(t, logical.UpdateOperation, "decode-token")
req.Data["encoded_token"] = encodedToken
req.Data["otp"] = otp
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("err: %v", err)
}
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
token, ok := resp.Data["token"]
if !ok {
t.Fatalf("did not get token back in response, response was %#v", resp.Data)
}
if token.(string) != tokenExpected {
t.Fatalf("bad token back: %s", token.(string))
}
datas := []map[string]interface{}{
nil,
{"encoded_token": encodedToken},
{"otp": otp},
}
for _, data := range datas {
req.Data = data
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
if err == nil {
t.Fatalf("no error despite missing payload")
}
schema.ValidateResponse(
t,
schema.GetResponseSchema(t, b.(*SystemBackend).Route(req.Path), req.Operation),
resp,
true,
)
}
}
func TestSystemBackend_auditHash(t *testing.T) {
c, b, _ := testCoreSystemBackend(t)
c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil)

View File

@ -0,0 +1,30 @@
---
layout: api
page_title: /sys/decode-token - HTTP API
description: The `/sys/decode-token` endpoint is used to decode the encoded token which is the result of /sys/generate-root.
---
# `/sys/decode-token`
The `/sys/decode-token` endpoint is used to decode the encoded token which is the result of the [/sys/generate-root](/vault/api-docs/system/generate-root) API.
## Parameters
- `encoded_token` `(string: <required>)`  Specifies the encoded token (result from /sys/generate-root).
- `otp` `(string: <required>)` - Specifies the otp code for decode.
## Sample Response
```json
{
"request_id": "9bc0fab8-d65c-3961-afe6-d05f50c5fd22",
"lease_id": "",
"lease_duration": 0,
"renewable": false,
"data": {
"token": "4RUmoevJ3lsLni9sTXcNnRE1"
},
"warnings": null
}
```

View File

@ -458,6 +458,10 @@
"title": "<code>/sys/generate-root</code>",
"path": "system/generate-root"
},
{
"title": "<code>/sys/decode-token</code>",
"path": "system/decode-token"
},
{
"title": "<code>/sys/health</code>",
"path": "system/health"