210 lines
5.3 KiB
Go
210 lines
5.3 KiB
Go
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/vault/helper/password"
|
|
"github.com/ryanuber/columnize"
|
|
)
|
|
|
|
// AuthCommand is a Command that handles authentication.
|
|
type AuthCommand struct {
|
|
Meta
|
|
}
|
|
|
|
func (c *AuthCommand) Run(args []string) int {
|
|
var method string
|
|
var methods bool
|
|
flags := c.Meta.FlagSet("auth", FlagSetDefault)
|
|
flags.BoolVar(&methods, "methods", false, "")
|
|
flags.StringVar(&method, "method", "", "method")
|
|
flags.Usage = func() { c.Ui.Error(c.Help()) }
|
|
if err := flags.Parse(args); err != nil {
|
|
return 1
|
|
}
|
|
|
|
if methods {
|
|
return c.listMethods()
|
|
}
|
|
|
|
args = flags.Args()
|
|
if len(args) > 1 {
|
|
flags.Usage()
|
|
c.Ui.Error("\nError: auth expects at most one argument")
|
|
return 1
|
|
}
|
|
if method != "" && len(args) > 0 {
|
|
flags.Usage()
|
|
c.Ui.Error("\nError: auth expects no arguments if -method is specified")
|
|
return 1
|
|
}
|
|
|
|
tokenHelper, err := c.TokenHelper()
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"Error initializing token helper: %s\n\n"+
|
|
"Please verify that the token helper is available and properly\n"+
|
|
"configured for your system. Please refer to the documentation\n"+
|
|
"on token helpers for more information.",
|
|
err))
|
|
return 1
|
|
}
|
|
|
|
// token is where the final token will go
|
|
var token string
|
|
if method == "" {
|
|
if len(args) > 0 {
|
|
token = args[0]
|
|
|
|
// TODO(mitchellh): stdin
|
|
} else {
|
|
// No arguments given, read the token from user input
|
|
fmt.Printf("Token (will be hidden): ")
|
|
token, err = password.Read(os.Stdin)
|
|
fmt.Printf("\n")
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"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"+
|
|
"pipe the token, please pass '-' as the token argument.\n\n"+
|
|
"Raw error: %s", err))
|
|
return 1
|
|
}
|
|
}
|
|
|
|
if token == "" {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"A token must be passed to auth. Please view the help\n" +
|
|
"for more information."))
|
|
return 1
|
|
}
|
|
} else {
|
|
// TODO(mitchellh): other auth methods
|
|
}
|
|
|
|
// Store the token!
|
|
if err := tokenHelper.Store(token); err != nil {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"Error storing token: %s\n\n"+
|
|
"Authentication was not successful and did not persist.\n"+
|
|
"Please reauthenticate, or fix the issue above if possible.",
|
|
err))
|
|
return 1
|
|
}
|
|
|
|
// Build the client so we can verify that the token is valid
|
|
client, err := c.Client()
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"Error initializing client to verify the token: %s", err))
|
|
return 1
|
|
}
|
|
|
|
// Verify the token
|
|
secret, err := client.Logical().Read("auth/token/lookup-self")
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"Error validating token: %s", err))
|
|
return 1
|
|
}
|
|
|
|
// Get the policies we have
|
|
policiesRaw, ok := secret.Data["policies"]
|
|
if !ok {
|
|
policiesRaw = []string{"unknown"}
|
|
}
|
|
var policies []string
|
|
for _, v := range policiesRaw.([]interface{}) {
|
|
policies = append(policies, v.(string))
|
|
}
|
|
|
|
c.Ui.Output(fmt.Sprintf(
|
|
"Successfully authenticated! The policies that are associated\n"+
|
|
"with this token are listed below:\n\n%s",
|
|
strings.Join(policies, ", "),
|
|
))
|
|
|
|
return 0
|
|
}
|
|
|
|
func (c *AuthCommand) listMethods() int {
|
|
client, err := c.Client()
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"Error initializing client: %s", err))
|
|
return 1
|
|
}
|
|
|
|
auth, err := client.Sys().ListAuth()
|
|
if err != nil {
|
|
c.Ui.Error(fmt.Sprintf(
|
|
"Error reading auth table: %s", err))
|
|
return 1
|
|
}
|
|
|
|
paths := make([]string, 0, len(auth))
|
|
for path, _ := range auth {
|
|
paths = append(paths, path)
|
|
}
|
|
sort.Strings(paths)
|
|
|
|
columns := []string{"Path | Type | Description"}
|
|
for _, k := range paths {
|
|
a := auth[k]
|
|
columns = append(columns, fmt.Sprintf(
|
|
"%s | %s | %s", k, a.Type, a.Description))
|
|
}
|
|
|
|
c.Ui.Output(columnize.SimpleFormat(columns))
|
|
return 0
|
|
}
|
|
|
|
func (c *AuthCommand) Synopsis() string {
|
|
return "Prints information about how to authenticate with Vault"
|
|
}
|
|
|
|
func (c *AuthCommand) Help() string {
|
|
helpText := `
|
|
Usage: vault auth [options] [token]
|
|
|
|
Authenticate with Vault with the given token or via any supported
|
|
authentication backend.
|
|
|
|
If no -method is specified, then the token is expected. If it is not
|
|
given on the command-line, it will be asked via user input. If the
|
|
token is "-", it will be read from stdin.
|
|
|
|
By specifying -method, alternate authentication methods can be used
|
|
such as OAuth or TLS certificates. For these, additional -var flags
|
|
may be required. It is an error to specify a token with -method.
|
|
|
|
General Options:
|
|
|
|
-address=TODO The address of the Vault server.
|
|
|
|
-ca-cert=path Path to a PEM encoded CA cert file to use to
|
|
verify the Vault server SSL certificate.
|
|
|
|
-ca-path=path Path to a directory of PEM encoded CA cert files
|
|
to verify the Vault server SSL certificate. If both
|
|
-ca-cert and -ca-path are specified, -ca-path is used.
|
|
|
|
-insecure Do not verify TLS certificate. This is highly
|
|
not recommended.
|
|
|
|
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.
|
|
|
|
-methods List the available auth methods.
|
|
|
|
`
|
|
return strings.TrimSpace(helpText)
|
|
}
|