From d1d3d697da30602b96ddc78528204ef58353ff25 Mon Sep 17 00:00:00 2001 From: l-with Date: Thu, 18 May 2023 21:18:19 +0200 Subject: [PATCH] Add possibility to decode generated encoded root token to api (#20595) --- changelog/20595.txt | 3 ++ vault/logical_system.go | 20 +++++++ vault/logical_system_paths.go | 26 +++++++++ vault/logical_system_test.go | 54 +++++++++++++++++++ .../content/api-docs/system/decode-token.mdx | 30 +++++++++++ website/data/api-docs-nav-data.json | 4 ++ 6 files changed, 137 insertions(+) create mode 100644 changelog/20595.txt create mode 100644 website/content/api-docs/system/decode-token.mdx diff --git a/changelog/20595.txt b/changelog/20595.txt new file mode 100644 index 000000000..982f41498 --- /dev/null +++ b/changelog/20595.txt @@ -0,0 +1,3 @@ +```release-note:improvement +core: Add possibility to decode a generated encoded root token via the rest API +``` diff --git a/vault/logical_system.go b/vault/logical_system.go index e6e93c3e8..4773f9de8 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -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, diff --git a/vault/logical_system_paths.go b/vault/logical_system_paths.go index 3e5ccdda7..ea3bc35ed 100644 --- a/vault/logical_system_paths.go +++ b/vault/logical_system_paths.go @@ -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{ diff --git a/vault/logical_system_test.go b/vault/logical_system_test.go index 3dcb6e5b3..7f62b45c4 100644 --- a/vault/logical_system_test.go +++ b/vault/logical_system_test.go @@ -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) diff --git a/website/content/api-docs/system/decode-token.mdx b/website/content/api-docs/system/decode-token.mdx new file mode 100644 index 000000000..01cbc336d --- /dev/null +++ b/website/content/api-docs/system/decode-token.mdx @@ -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: )` – Specifies the encoded token (result from /sys/generate-root). + +- `otp` `(string: )` - 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 +} +``` diff --git a/website/data/api-docs-nav-data.json b/website/data/api-docs-nav-data.json index e15b00620..a34798af7 100644 --- a/website/data/api-docs-nav-data.json +++ b/website/data/api-docs-nav-data.json @@ -458,6 +458,10 @@ "title": "/sys/generate-root", "path": "system/generate-root" }, + { + "title": "/sys/decode-token", + "path": "system/decode-token" + }, { "title": "/sys/health", "path": "system/health"