Change auth helper interface to api.Secret. (#3263)
This allows us to properly handle wrapped responses. Fixes #3217
This commit is contained in:
parent
9a159a597f
commit
223c4fc325
|
@ -69,7 +69,7 @@ func GenerateLoginData(accessKey, secretKey, sessionToken, headerValue string) (
|
|||
return loginData, nil
|
||||
}
|
||||
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
|
||||
mount, ok := m["mount"]
|
||||
if !ok {
|
||||
mount = "aws"
|
||||
|
@ -87,23 +87,23 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
|
||||
loginData, err := GenerateLoginData(m["aws_access_key_id"], m["aws_secret_access_key"], m["aws_security_token"], headerValue)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
if loginData == nil {
|
||||
return "", fmt.Errorf("got nil response from GenerateLoginData")
|
||||
return nil, fmt.Errorf("got nil response from GenerateLoginData")
|
||||
}
|
||||
loginData["role"] = role
|
||||
path := fmt.Sprintf("auth/%s/login", mount)
|
||||
secret, err := c.Logical().Write(path, loginData)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return "", fmt.Errorf("empty response from credential provider")
|
||||
return nil, fmt.Errorf("empty response from credential provider")
|
||||
}
|
||||
|
||||
return secret.Auth.ClientToken, nil
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func (h *CLIHandler) Help() string {
|
||||
|
|
|
@ -10,13 +10,13 @@ import (
|
|||
|
||||
type CLIHandler struct{}
|
||||
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
|
||||
var data struct {
|
||||
Mount string `mapstructure:"mount"`
|
||||
Name string `mapstructure:"name"`
|
||||
}
|
||||
if err := mapstructure.WeakDecode(m, &data); err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if data.Mount == "" {
|
||||
|
@ -29,13 +29,13 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
path := fmt.Sprintf("auth/%s/login", data.Mount)
|
||||
secret, err := c.Logical().Write(path, options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return "", fmt.Errorf("empty response from credential provider")
|
||||
return nil, fmt.Errorf("empty response from credential provider")
|
||||
}
|
||||
|
||||
return secret.Auth.ClientToken, nil
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func (h *CLIHandler) Help() string {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
type CLIHandler struct{}
|
||||
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
|
||||
mount, ok := m["mount"]
|
||||
if !ok {
|
||||
mount = "github"
|
||||
|
@ -19,7 +19,7 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
token, ok := m["token"]
|
||||
if !ok {
|
||||
if token = os.Getenv("VAULT_AUTH_GITHUB_TOKEN"); token == "" {
|
||||
return "", fmt.Errorf("GitHub token should be provided either as 'value' for 'token' key,\nor via an env var VAULT_AUTH_GITHUB_TOKEN")
|
||||
return nil, fmt.Errorf("GitHub token should be provided either as 'value' for 'token' key,\nor via an env var VAULT_AUTH_GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,13 +28,13 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
"token": token,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return "", fmt.Errorf("empty response from credential provider")
|
||||
return nil, fmt.Errorf("empty response from credential provider")
|
||||
}
|
||||
|
||||
return secret.Auth.ClientToken, nil
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func (h *CLIHandler) Help() string {
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
type CLIHandler struct{}
|
||||
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
|
||||
mount, ok := m["mount"]
|
||||
if !ok {
|
||||
mount = "ldap"
|
||||
|
@ -21,7 +21,7 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
if !ok {
|
||||
username = usernameFromEnv()
|
||||
if username == "" {
|
||||
return "", fmt.Errorf("'username' not supplied and neither 'LOGNAME' nor 'USER' env vars set")
|
||||
return nil, fmt.Errorf("'username' not supplied and neither 'LOGNAME' nor 'USER' env vars set")
|
||||
}
|
||||
}
|
||||
password, ok := m["password"]
|
||||
|
@ -31,7 +31,7 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
password, err = pwd.Read(os.Stdin)
|
||||
fmt.Println()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,13 +51,13 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
path := fmt.Sprintf("auth/%s/login/%s", mount, username)
|
||||
secret, err := c.Logical().Write(path, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return "", fmt.Errorf("empty response from credential provider")
|
||||
return nil, fmt.Errorf("empty response from credential provider")
|
||||
}
|
||||
|
||||
return secret.Auth.ClientToken, nil
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func (h *CLIHandler) Help() string {
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
type CLIHandler struct{}
|
||||
|
||||
// Auth cli method
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
|
||||
mount, ok := m["mount"]
|
||||
if !ok {
|
||||
mount = "okta"
|
||||
|
@ -21,7 +21,7 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
|
||||
username, ok := m["username"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("'username' var must be set")
|
||||
return nil, fmt.Errorf("'username' var must be set")
|
||||
}
|
||||
password, ok := m["password"]
|
||||
if !ok {
|
||||
|
@ -30,7 +30,7 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
password, err = pwd.Read(os.Stdin)
|
||||
fmt.Println()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,13 +41,13 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
path := fmt.Sprintf("auth/%s/login/%s", mount, username)
|
||||
secret, err := c.Logical().Write(path, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return "", fmt.Errorf("empty response from credential provider")
|
||||
return nil, fmt.Errorf("empty response from credential provider")
|
||||
}
|
||||
|
||||
return secret.Auth.ClientToken, nil
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
// Help method for okta cli
|
||||
|
|
|
@ -14,7 +14,7 @@ type CLIHandler struct {
|
|||
DefaultMount string
|
||||
}
|
||||
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
||||
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
|
||||
var data struct {
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
|
@ -23,18 +23,18 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
Passcode string `mapstructure:"passcode"`
|
||||
}
|
||||
if err := mapstructure.WeakDecode(m, &data); err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if data.Username == "" {
|
||||
return "", fmt.Errorf("'username' must be specified")
|
||||
return nil, fmt.Errorf("'username' must be specified")
|
||||
}
|
||||
if data.Password == "" {
|
||||
fmt.Printf("Password (will be hidden): ")
|
||||
password, err := pwd.Read(os.Stdin)
|
||||
fmt.Println()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
data.Password = password
|
||||
}
|
||||
|
@ -55,13 +55,13 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
|||
path := fmt.Sprintf("auth/%s/login/%s", data.Mount, data.Username)
|
||||
secret, err := c.Logical().Write(path, options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return "", fmt.Errorf("empty response from credential provider")
|
||||
return nil, fmt.Errorf("empty response from credential provider")
|
||||
}
|
||||
|
||||
return secret.Auth.ClientToken, nil
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func (h *CLIHandler) Help() string {
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
// AuthHandler is the interface that any auth handlers must implement
|
||||
// to enable auth via the CLI.
|
||||
type AuthHandler interface {
|
||||
Auth(*api.Client, map[string]string) (string, error)
|
||||
Auth(*api.Client, map[string]string) (*api.Secret, error)
|
||||
Help() string
|
||||
}
|
||||
|
||||
|
@ -167,11 +167,52 @@ func (c *AuthCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
// Authenticate
|
||||
token, err := handler.Auth(client, vars)
|
||||
secret, err := handler.Auth(client, vars)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
if secret == nil {
|
||||
c.Ui.Error("Empty response from auth helper")
|
||||
return 1
|
||||
}
|
||||
|
||||
// If we had requested a wrapped token, we want to unset that request
|
||||
// before performing further functions
|
||||
client.SetWrappingLookupFunc(func(string, string) string {
|
||||
return ""
|
||||
})
|
||||
|
||||
CHECK_TOKEN:
|
||||
var token string
|
||||
switch {
|
||||
case secret == nil:
|
||||
c.Ui.Error("Empty response from auth helper")
|
||||
return 1
|
||||
|
||||
case secret.Auth != nil:
|
||||
token = secret.Auth.ClientToken
|
||||
|
||||
case secret.WrapInfo != nil:
|
||||
if secret.WrapInfo.WrappedAccessor == "" {
|
||||
c.Ui.Error("Got a wrapped response from Vault but wrapped reply does not seem to contain a token")
|
||||
return 1
|
||||
}
|
||||
if tokenOnly {
|
||||
c.Ui.Output(secret.WrapInfo.Token)
|
||||
return 0
|
||||
}
|
||||
if noStore {
|
||||
return OutputSecret(c.Ui, "table", secret)
|
||||
}
|
||||
client.SetToken(secret.WrapInfo.Token)
|
||||
secret, err = client.Logical().Unwrap("")
|
||||
goto CHECK_TOKEN
|
||||
|
||||
default:
|
||||
c.Ui.Error("No auth or wrapping info in auth helper response")
|
||||
return 1
|
||||
}
|
||||
|
||||
// Cache the previous token so that it can be restored if authentication fails
|
||||
var previousToken string
|
||||
|
@ -230,6 +271,9 @@ func (c *AuthCommand) Run(args []string) int {
|
|||
}
|
||||
return 1
|
||||
}
|
||||
client.SetWrappingLookupFunc(func(string, string) string {
|
||||
return ""
|
||||
})
|
||||
|
||||
// If in no-store mode it won't have read the token from a token-helper (or
|
||||
// will read an old one) so set it explicitly
|
||||
|
@ -238,7 +282,7 @@ func (c *AuthCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
// Verify the token
|
||||
secret, err := client.Auth().Token().LookupSelf()
|
||||
secret, err = client.Auth().Token().LookupSelf()
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf(
|
||||
"Error validating token: %s", err))
|
||||
|
@ -274,8 +318,8 @@ func (c *AuthCommand) Run(args []string) int {
|
|||
|
||||
// Get the policies we have
|
||||
policiesRaw, ok := secret.Data["policies"]
|
||||
if !ok {
|
||||
policiesRaw = []string{"unknown"}
|
||||
if !ok || policiesRaw == nil {
|
||||
policiesRaw = []interface{}{"unknown"}
|
||||
}
|
||||
var policies []string
|
||||
for _, v := range policiesRaw.([]interface{}) {
|
||||
|
@ -307,6 +351,9 @@ func (c *AuthCommand) getMethods() (map[string]*api.AuthMount, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.SetWrappingLookupFunc(func(string, string) string {
|
||||
return ""
|
||||
})
|
||||
|
||||
auth, err := client.Sys().ListAuth()
|
||||
if err != nil {
|
||||
|
@ -387,15 +434,21 @@ Usage: vault auth [options] [auth-information]
|
|||
The value of the "-path" flag is supplied to auth providers as the "mount"
|
||||
option in the payload to specify the mount point.
|
||||
|
||||
If response wrapping is used (via -wrap-ttl), the returned token will be
|
||||
automatically unwrapped unless:
|
||||
* -token-only is used, in which case the wrapping token will be output
|
||||
* -no-store is used, in which case the details of the wrapping token
|
||||
will be printed
|
||||
|
||||
General Options:
|
||||
|
||||
` + meta.GeneralOptionsUsage() + `
|
||||
|
||||
Auth Options:
|
||||
|
||||
-method=name Outputs help for the authentication method with the given
|
||||
name for the remote server. If this authentication method
|
||||
is not available, exit with code 1.
|
||||
-method=name Use the method given here, which is a type of backend, not
|
||||
the path. If this authentication method is not available,
|
||||
exit with code 1.
|
||||
|
||||
-method-help If set, the help for the selected method will be shown.
|
||||
|
||||
|
@ -422,7 +475,7 @@ type tokenAuthHandler struct {
|
|||
Token string
|
||||
}
|
||||
|
||||
func (h *tokenAuthHandler) Auth(*api.Client, map[string]string) (string, error) {
|
||||
func (h *tokenAuthHandler) Auth(*api.Client, map[string]string) (*api.Secret, error) {
|
||||
token := h.Token
|
||||
if token == "" {
|
||||
var err error
|
||||
|
@ -432,7 +485,7 @@ func (h *tokenAuthHandler) Auth(*api.Client, map[string]string) (string, error)
|
|||
token, err = password.Read(os.Stdin)
|
||||
fmt.Printf("\n")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(
|
||||
return nil, fmt.Errorf(
|
||||
"Error attempting to ask for token. The raw error message\n"+
|
||||
"is shown below, but the most common reason for this error is\n"+
|
||||
"that you attempted to pipe a value into auth. If you want to\n"+
|
||||
|
@ -442,12 +495,16 @@ func (h *tokenAuthHandler) Auth(*api.Client, map[string]string) (string, error)
|
|||
}
|
||||
|
||||
if token == "" {
|
||||
return "", fmt.Errorf(
|
||||
return nil, fmt.Errorf(
|
||||
"A token must be passed to auth. Please view the help\n" +
|
||||
"for more information.")
|
||||
}
|
||||
|
||||
return token, nil
|
||||
return &api.Secret{
|
||||
Auth: &api.SecretAuth{
|
||||
ClientToken: token,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *tokenAuthHandler) Help() string {
|
||||
|
|
|
@ -9,6 +9,9 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/http"
|
||||
"github.com/hashicorp/vault/meta"
|
||||
|
@ -84,6 +87,155 @@ func TestAuth_token(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAuth_wrapping(t *testing.T) {
|
||||
baseConfig := &vault.CoreConfig{
|
||||
CredentialBackends: map[string]logical.Factory{
|
||||
"userpass": credUserpass.Factory,
|
||||
},
|
||||
}
|
||||
cluster := vault.NewTestCluster(t, baseConfig, &vault.TestClusterOptions{
|
||||
HandlerFunc: http.Handler,
|
||||
BaseListenAddress: "127.0.0.1:8200",
|
||||
})
|
||||
cluster.Start()
|
||||
defer cluster.Cleanup()
|
||||
|
||||
testAuthInit(t)
|
||||
|
||||
client := cluster.Cores[0].Client
|
||||
err := client.Sys().EnableAuthWithOptions("userpass", &api.EnableAuthOptions{
|
||||
Type: "userpass",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = client.Logical().Write("auth/userpass/users/foo", map[string]interface{}{
|
||||
"password": "bar",
|
||||
"policies": "zip,zap",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &AuthCommand{
|
||||
Meta: meta.Meta{
|
||||
Ui: ui,
|
||||
TokenHelper: DefaultTokenHelper,
|
||||
},
|
||||
Handlers: map[string]AuthHandler{
|
||||
"userpass": &credUserpass.CLIHandler{DefaultMount: "userpass"},
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-address",
|
||||
"https://127.0.0.1:8200",
|
||||
"-tls-skip-verify",
|
||||
"-method",
|
||||
"userpass",
|
||||
"username=foo",
|
||||
"password=bar",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
// Test again with wrapping
|
||||
ui = new(cli.MockUi)
|
||||
c = &AuthCommand{
|
||||
Meta: meta.Meta{
|
||||
Ui: ui,
|
||||
TokenHelper: DefaultTokenHelper,
|
||||
},
|
||||
Handlers: map[string]AuthHandler{
|
||||
"userpass": &credUserpass.CLIHandler{DefaultMount: "userpass"},
|
||||
},
|
||||
}
|
||||
|
||||
args = []string{
|
||||
"-address",
|
||||
"https://127.0.0.1:8200",
|
||||
"-tls-skip-verify",
|
||||
"-wrap-ttl",
|
||||
"5m",
|
||||
"-method",
|
||||
"userpass",
|
||||
"username=foo",
|
||||
"password=bar",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
// Test again with no-store
|
||||
ui = new(cli.MockUi)
|
||||
c = &AuthCommand{
|
||||
Meta: meta.Meta{
|
||||
Ui: ui,
|
||||
TokenHelper: DefaultTokenHelper,
|
||||
},
|
||||
Handlers: map[string]AuthHandler{
|
||||
"userpass": &credUserpass.CLIHandler{DefaultMount: "userpass"},
|
||||
},
|
||||
}
|
||||
|
||||
args = []string{
|
||||
"-address",
|
||||
"https://127.0.0.1:8200",
|
||||
"-tls-skip-verify",
|
||||
"-wrap-ttl",
|
||||
"5m",
|
||||
"-no-store",
|
||||
"-method",
|
||||
"userpass",
|
||||
"username=foo",
|
||||
"password=bar",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
// Test again with wrapping and token-only
|
||||
ui = new(cli.MockUi)
|
||||
c = &AuthCommand{
|
||||
Meta: meta.Meta{
|
||||
Ui: ui,
|
||||
TokenHelper: DefaultTokenHelper,
|
||||
},
|
||||
Handlers: map[string]AuthHandler{
|
||||
"userpass": &credUserpass.CLIHandler{DefaultMount: "userpass"},
|
||||
},
|
||||
}
|
||||
|
||||
args = []string{
|
||||
"-address",
|
||||
"https://127.0.0.1:8200",
|
||||
"-tls-skip-verify",
|
||||
"-wrap-ttl",
|
||||
"5m",
|
||||
"-token-only",
|
||||
"-method",
|
||||
"userpass",
|
||||
"username=foo",
|
||||
"password=bar",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
token := strings.TrimSpace(ui.OutputWriter.String())
|
||||
if token == "" {
|
||||
t.Fatal("expected to find token in output")
|
||||
}
|
||||
secret, err := client.Logical().Unwrap(token)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if secret.Auth.ClientToken == "" {
|
||||
t.Fatal("no client token found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_token_nostore(t *testing.T) {
|
||||
core, _, token := vault.TestCoreUnsealed(t)
|
||||
ln, addr := http.TestServer(t, core)
|
||||
|
@ -237,8 +389,12 @@ func testAuthInit(t *testing.T) {
|
|||
|
||||
type testAuthHandler struct{}
|
||||
|
||||
func (h *testAuthHandler) Auth(c *api.Client, m map[string]string) (string, error) {
|
||||
return m["foo"], nil
|
||||
func (h *testAuthHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
|
||||
return &api.Secret{
|
||||
Auth: &api.SecretAuth{
|
||||
ClientToken: m["foo"],
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *testAuthHandler) Help() string { return "" }
|
||||
|
|
Loading…
Reference in New Issue