mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 03:27:54 +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"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/hashicorp/errwrap"
|
"github.com/hashicorp/errwrap"
|
||||||
@@ -46,8 +47,26 @@ func (c *Client) Logical() *Logical {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Logical) Read(path string) (*Secret, error) {
|
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)
|
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())
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
defer cancelFunc()
|
defer cancelFunc()
|
||||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
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
|
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
|
// 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 duration is less than 1s, it is returned as 0. The integer represents
|
||||||
// the whole number unit of seconds for the duration.
|
// the whole number unit of seconds for the duration.
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
@@ -13,6 +15,8 @@ var _ cli.CommandAutocomplete = (*ReadCommand)(nil)
|
|||||||
|
|
||||||
type ReadCommand struct {
|
type ReadCommand struct {
|
||||||
*BaseCommand
|
*BaseCommand
|
||||||
|
|
||||||
|
testStdin io.Reader // for tests
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ReadCommand) Synopsis() string {
|
func (c *ReadCommand) Synopsis() string {
|
||||||
@@ -63,9 +67,6 @@ func (c *ReadCommand) Run(args []string) int {
|
|||||||
case len(args) < 1:
|
case len(args) < 1:
|
||||||
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
|
c.UI.Error(fmt.Sprintf("Not enough arguments (expected 1, got %d)", len(args)))
|
||||||
return 1
|
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()
|
client, err := c.Client()
|
||||||
@@ -74,9 +75,21 @@ func (c *ReadCommand) Run(args []string) int {
|
|||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pull our fake stdin if needed
|
||||||
|
stdin := (io.Reader)(os.Stdin)
|
||||||
|
if c.testStdin != nil {
|
||||||
|
stdin = c.testStdin
|
||||||
|
}
|
||||||
|
|
||||||
path := sanitizePath(args[0])
|
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 {
|
if err != nil {
|
||||||
c.UI.Error(fmt.Sprintf("Error reading %s: %s", path, err))
|
c.UI.Error(fmt.Sprintf("Error reading %s: %s", path, err))
|
||||||
return 2
|
return 2
|
||||||
|
|||||||
@@ -28,75 +28,79 @@ func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Reques
|
|||||||
return nil, http.StatusNotFound, nil
|
return nil, http.StatusNotFound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var data map[string]interface{}
|
||||||
|
|
||||||
// Determine the operation
|
// Determine the operation
|
||||||
var op logical.Operation
|
var op logical.Operation
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case "DELETE":
|
case "DELETE":
|
||||||
op = logical.DeleteOperation
|
op = logical.DeleteOperation
|
||||||
|
|
||||||
case "GET":
|
case "GET":
|
||||||
op = logical.ReadOperation
|
op = logical.ReadOperation
|
||||||
// Need to call ParseForm to get query params loaded
|
|
||||||
queryVals := r.URL.Query()
|
queryVals := r.URL.Query()
|
||||||
|
var list bool
|
||||||
|
var err error
|
||||||
listStr := queryVals.Get("list")
|
listStr := queryVals.Get("list")
|
||||||
if listStr != "" {
|
if listStr != "" {
|
||||||
list, err := strconv.ParseBool(listStr)
|
list, err = strconv.ParseBool(listStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, http.StatusBadRequest, nil
|
return nil, http.StatusBadRequest, nil
|
||||||
}
|
}
|
||||||
if list {
|
if list {
|
||||||
op = logical.ListOperation
|
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":
|
case "POST", "PUT":
|
||||||
op = logical.UpdateOperation
|
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":
|
case "LIST":
|
||||||
op = logical.ListOperation
|
op = logical.ListOperation
|
||||||
case "OPTIONS":
|
|
||||||
default:
|
|
||||||
return nil, http.StatusMethodNotAllowed, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if op == logical.ListOperation {
|
|
||||||
if !strings.HasSuffix(path, "/") {
|
if !strings.HasSuffix(path, "/") {
|
||||||
path += "/"
|
path += "/"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the request if we can
|
case "OPTIONS":
|
||||||
var data map[string]interface{}
|
default:
|
||||||
if op == logical.UpdateOperation {
|
return nil, http.StatusMethodNotAllowed, nil
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
Reference in New Issue
Block a user