Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: add new -header option to be able to add headers to all cli http request #12508

Merged
merged 1 commit into from Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/12508.txt
@@ -0,0 +1,3 @@
```release-note:improvement
cli: add new http option : -header which enable sending arbitrary headers with the cli
```
28 changes: 28 additions & 0 deletions command/base.go
Expand Up @@ -58,6 +58,8 @@ type BaseCommand struct {

flagMFA []string

flagHeader map[string]string

tokenHelper token.TokenHelper

client *api.Client
Expand Down Expand Up @@ -154,6 +156,23 @@ func (c *BaseCommand) Client() (*api.Client, error) {
client.SetPolicyOverride(c.flagPolicyOverride)
}

if c.flagHeader != nil {

var forbiddenHeaders []string
for key, val := range c.flagHeader {

if strings.HasPrefix(key, "X-Vault-") {
forbiddenHeaders = append(forbiddenHeaders, key)
continue
}
client.AddHeader(key, val)
}

if len(forbiddenHeaders) > 0 {
return nil, fmt.Errorf("failed to setup Headers[%s]: Header starting by 'X-Vault-' are for internal usage only", strings.Join(forbiddenHeaders, ", "))
}
}

c.client = client

return client, nil
Expand Down Expand Up @@ -365,6 +384,15 @@ func (c *BaseCommand) flagSet(bit FlagSetBit) *FlagSets {
Usage: "Key to unlock a namespace API lock.",
})

f.StringMapVar(&StringMapVar{
Name: "header",
Target: &c.flagHeader,
Completion: complete.PredictAnything,
Usage: "Key-value pair provided as key=value to provide http header added to any request done by the CLI." +
"Trying to add headers starting with 'X-Vault-' is forbidden and will make the command fail " +
"This can be specified multiple times.",
})

}

if bit&(FlagSetOutputField|FlagSetOutputFormat) != 0 {
Expand Down
69 changes: 69 additions & 0 deletions command/base_test.go
@@ -0,0 +1,69 @@
package command

import (
"net/http"
"reflect"
"testing"
)

func getDefaultCliHeaders(t *testing.T) http.Header {
bc := &BaseCommand{}
cli, err := bc.Client()
if err != nil {
t.Fatal(err)
}
return cli.Headers()
}

func TestClient_FlagHeader(t *testing.T) {
defaultHeaders := getDefaultCliHeaders(t)

cases := []struct {
Input map[string]string
Valid bool
}{
{
map[string]string{},
true,
},
{
map[string]string{"foo": "bar", "header2": "value2"},
true,
},
{
map[string]string{"X-Vault-foo": "bar", "header2": "value2"},
false,
},
}

for _, tc := range cases {
expectedHeaders := defaultHeaders.Clone()
for key, val := range tc.Input {
expectedHeaders.Add(key, val)
}

bc := &BaseCommand{flagHeader: tc.Input}
cli, err := bc.Client()

if err == nil && !tc.Valid {
t.Errorf("No error for input[%#v], but not valid", tc.Input)
continue
}

if err != nil {
if tc.Valid {
t.Errorf("Error[%v] with input[%#v], but valid", err, tc.Input)
}
continue
}

if cli == nil {
t.Error("client should not be nil")
}

actualHeaders := cli.Headers()
if !reflect.DeepEqual(expectedHeaders, actualHeaders) {
t.Errorf("expected [%#v] but got [%#v]", expectedHeaders, actualHeaders)
}
}
}