mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
Add support for passing args via vault read (#5093)
We support this in the API as of 0.10.2 so read should support it too.
Trivially tested with some log info:
`core: data: data="map[string]interface {}{"zip":[]string{"zap", "zap2"}}"`
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
@@ -46,8 +47,26 @@ func (c *Client) Logical() *Logical {
|
||||
}
|
||||
|
||||
func (c *Logical) Read(path string) (*Secret, error) {
|
||||
return c.ReadWithData(path, nil)
|
||||
}
|
||||
|
||||
func (c *Logical) ReadWithData(path string, data map[string][]string) (*Secret, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/"+path)
|
||||
|
||||
var values url.Values
|
||||
for k, v := range data {
|
||||
if values == nil {
|
||||
values = make(url.Values)
|
||||
}
|
||||
for _, val := range v {
|
||||
values.Add(k, val)
|
||||
}
|
||||
}
|
||||
|
||||
if values != nil {
|
||||
r.Params = values
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
|
||||
@@ -152,6 +152,22 @@ func parseArgsDataString(stdin io.Reader, args []string) (map[string]string, err
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// parseArgsDataStringLists parses the args data and returns the values as
|
||||
// string lists. If the values cannot be represented as strings, an error is
|
||||
// returned.
|
||||
func parseArgsDataStringLists(stdin io.Reader, args []string) (map[string][]string, error) {
|
||||
raw, err := parseArgsData(stdin, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result map[string][]string
|
||||
if err := mapstructure.WeakDecode(raw, &result); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert values to strings")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// truncateToSeconds truncates the given duration to the number of seconds. If
|
||||
// the duration is less than 1s, it is returned as 0. The integer represents
|
||||
// the whole number unit of seconds for the duration.
|
||||
|
||||
@@ -2,6 +2,8 @@ package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
@@ -13,6 +15,8 @@ var _ cli.CommandAutocomplete = (*ReadCommand)(nil)
|
||||
|
||||
type ReadCommand struct {
|
||||
*BaseCommand
|
||||
|
||||
testStdin io.Reader // for tests
|
||||
}
|
||||
|
||||
func (c *ReadCommand) Synopsis() string {
|
||||
@@ -63,9 +67,6 @@ func (c *ReadCommand) Run(args []string) int {
|
||||
case len(args) < 1:
|
||||
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
|
||||
return 1
|
||||
case len(args) > 1:
|
||||
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
|
||||
return 1
|
||||
}
|
||||
|
||||
client, err := c.Client()
|
||||
@@ -74,9 +75,21 @@ func (c *ReadCommand) Run(args []string) int {
|
||||
return 2
|
||||
}
|
||||
|
||||
// Pull our fake stdin if needed
|
||||
stdin := (io.Reader)(os.Stdin)
|
||||
if c.testStdin != nil {
|
||||
stdin = c.testStdin
|
||||
}
|
||||
|
||||
path := sanitizePath(args[0])
|
||||
|
||||
secret, err := client.Logical().Read(path)
|
||||
data, err := parseArgsDataStringLists(stdin, args[1:])
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Failed to parse K=V data: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
secret, err := client.Logical().ReadWithData(path, data)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error reading %s: %s", path, err))
|
||||
return 2
|
||||
|
||||
@@ -28,75 +28,79 @@ func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Reques
|
||||
return nil, http.StatusNotFound, nil
|
||||
}
|
||||
|
||||
var data map[string]interface{}
|
||||
|
||||
// Determine the operation
|
||||
var op logical.Operation
|
||||
switch r.Method {
|
||||
case "DELETE":
|
||||
op = logical.DeleteOperation
|
||||
|
||||
case "GET":
|
||||
op = logical.ReadOperation
|
||||
// Need to call ParseForm to get query params loaded
|
||||
queryVals := r.URL.Query()
|
||||
var list bool
|
||||
var err error
|
||||
listStr := queryVals.Get("list")
|
||||
if listStr != "" {
|
||||
list, err := strconv.ParseBool(listStr)
|
||||
list, err = strconv.ParseBool(listStr)
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, nil
|
||||
}
|
||||
if list {
|
||||
op = logical.ListOperation
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
path += "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !list {
|
||||
getData := map[string]interface{}{}
|
||||
|
||||
for k, v := range r.URL.Query() {
|
||||
// Skip the help key as this is a reserved parameter
|
||||
if k == "help" {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(v) == 0:
|
||||
case len(v) == 1:
|
||||
getData[k] = v[0]
|
||||
default:
|
||||
getData[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(getData) > 0 {
|
||||
data = getData
|
||||
}
|
||||
}
|
||||
|
||||
case "POST", "PUT":
|
||||
op = logical.UpdateOperation
|
||||
// Parse the request if we can
|
||||
if op == logical.UpdateOperation {
|
||||
err := parseRequest(r, w, &data)
|
||||
if err == io.EOF {
|
||||
data = nil
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, err
|
||||
}
|
||||
}
|
||||
|
||||
case "LIST":
|
||||
op = logical.ListOperation
|
||||
case "OPTIONS":
|
||||
default:
|
||||
return nil, http.StatusMethodNotAllowed, nil
|
||||
}
|
||||
|
||||
if op == logical.ListOperation {
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
path += "/"
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the request if we can
|
||||
var data map[string]interface{}
|
||||
if op == logical.UpdateOperation {
|
||||
err := parseRequest(r, w, &data)
|
||||
if err == io.EOF {
|
||||
data = nil
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, err
|
||||
}
|
||||
}
|
||||
|
||||
// If we are a read operation, try and parse any parameters
|
||||
if op == logical.ReadOperation {
|
||||
getData := map[string]interface{}{}
|
||||
|
||||
for k, v := range r.URL.Query() {
|
||||
// Skip the help key as this is a reserved parameter
|
||||
if k == "help" {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(v) == 0:
|
||||
case len(v) == 1:
|
||||
getData[k] = v[0]
|
||||
default:
|
||||
getData[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(getData) > 0 {
|
||||
data = getData
|
||||
}
|
||||
case "OPTIONS":
|
||||
default:
|
||||
return nil, http.StatusMethodNotAllowed, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
Reference in New Issue
Block a user