Add possibility to decode generated encoded root token to api (#20595)
This commit is contained in:
parent
f9fdac0345
commit
d1d3d697da
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
core: Add possibility to decode a generated encoded root token via the rest API
|
||||||
|
```
|
|
@ -44,6 +44,7 @@ import (
|
||||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||||
"github.com/hashicorp/vault/sdk/helper/jsonutil"
|
"github.com/hashicorp/vault/sdk/helper/jsonutil"
|
||||||
"github.com/hashicorp/vault/sdk/helper/pluginutil"
|
"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/helper/wrapping"
|
||||||
"github.com/hashicorp/vault/sdk/logical"
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
"github.com/hashicorp/vault/version"
|
"github.com/hashicorp/vault/version"
|
||||||
|
@ -150,6 +151,7 @@ func NewSystemBackend(core *Core, logger log.Logger) *SystemBackend {
|
||||||
"health",
|
"health",
|
||||||
"generate-root/attempt",
|
"generate-root/attempt",
|
||||||
"generate-root/update",
|
"generate-root/update",
|
||||||
|
"decode-token",
|
||||||
"rekey/init",
|
"rekey/init",
|
||||||
"rekey/update",
|
"rekey/update",
|
||||||
"rekey/verify",
|
"rekey/verify",
|
||||||
|
@ -923,6 +925,24 @@ func (b *SystemBackend) handleRekeyDeleteRecovery(ctx context.Context, req *logi
|
||||||
return b.handleRekeyDelete(ctx, req, data, true)
|
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{} {
|
func (b *SystemBackend) mountInfo(ctx context.Context, entry *MountEntry) map[string]interface{} {
|
||||||
info := map[string]interface{}{
|
info := map[string]interface{}{
|
||||||
"type": entry.Type,
|
"type": entry.Type,
|
||||||
|
|
|
@ -466,6 +466,32 @@ func (b *SystemBackend) configPaths() []*framework.Path {
|
||||||
HelpSynopsis: strings.TrimSpace(sysHelp["generate-root"][0]),
|
HelpSynopsis: strings.TrimSpace(sysHelp["generate-root"][0]),
|
||||||
HelpDescription: strings.TrimSpace(sysHelp["generate-root"][1]),
|
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$",
|
Pattern: "health$",
|
||||||
Fields: map[string]*framework.FieldSchema{
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
|
|
@ -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) {
|
func TestSystemBackend_auditHash(t *testing.T) {
|
||||||
c, b, _ := testCoreSystemBackend(t)
|
c, b, _ := testCoreSystemBackend(t)
|
||||||
c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil)
|
c.auditBackends["noop"] = corehelpers.NoopAuditFactory(nil)
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
```
|
|
@ -458,6 +458,10 @@
|
||||||
"title": "<code>/sys/generate-root</code>",
|
"title": "<code>/sys/generate-root</code>",
|
||||||
"path": "system/generate-root"
|
"path": "system/generate-root"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "<code>/sys/decode-token</code>",
|
||||||
|
"path": "system/decode-token"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "<code>/sys/health</code>",
|
"title": "<code>/sys/health</code>",
|
||||||
"path": "system/health"
|
"path": "system/health"
|
||||||
|
|
Loading…
Reference in New Issue