etcdctl: add flags for specifying password

This commit adds two flags to etcdctl:
1. `--password` flag to etcdctl as a global option. It can be used for
specifying password for authentication required for the command
execution.
2. `--new-user-password` flag to `etcdctl user add`. It can be used
for specifying password of newly created user by the command.

The main motivation of the flags is allowing user to have : in its
name.

Fix https://github.com/coreos/etcd/issues/9691
This commit is contained in:
Hitoshi Mitake 2018-05-17 13:21:27 +09:00
parent 1b9791c6bd
commit 8fcab98bf2
4 changed files with 46 additions and 21 deletions

View File

@ -32,7 +32,7 @@ Creating a user is as easy as
$ etcdctl user add myusername
```
Creating a new user will prompt for a new password. The password can be supplied from standard input when an option `--interactive=false` is given.
Creating a new user will prompt for a new password. The password can be supplied from standard input when an option `--interactive=false` is given. `--new-user-password` can also be used for supplying the password.
Roles can be granted and revoked for a user with:
@ -157,6 +157,13 @@ The password can be taken from a prompt:
$ etcdctl --user user get foo
```
The password can also be taken from a command line flag `--password`:
```
$ etcdctl --user user --password password get foo
```
Otherwise, all `etcdctl` commands remain the same. Users and roles can still be created and modified, but require authentication by a user with the root role.
## Using TLS Common Name

View File

@ -53,7 +53,8 @@ type GlobalFlags struct {
OutputFormat string
IsHex bool
User string
User string
Password string
Debug bool
}
@ -341,6 +342,10 @@ func authCfgFromCmd(cmd *cobra.Command) *authCfg {
if err != nil {
ExitWithError(ExitBadArgs, err)
}
passwordFlag, err := cmd.Flags().GetString("password")
if err != nil {
ExitWithError(ExitBadArgs, err)
}
if userFlag == "" {
return nil
@ -348,16 +353,21 @@ func authCfgFromCmd(cmd *cobra.Command) *authCfg {
var cfg authCfg
splitted := strings.SplitN(userFlag, ":", 2)
if len(splitted) < 2 {
cfg.username = userFlag
cfg.password, err = speakeasy.Ask("Password: ")
if err != nil {
ExitWithError(ExitError, err)
if passwordFlag == "" {
splitted := strings.SplitN(userFlag, ":", 2)
if len(splitted) < 2 {
cfg.username = userFlag
cfg.password, err = speakeasy.Ask("Password: ")
if err != nil {
ExitWithError(ExitError, err)
}
} else {
cfg.username = splitted[0]
cfg.password = splitted[1]
}
} else {
cfg.username = splitted[0]
cfg.password = splitted[1]
cfg.username = userFlag
cfg.password = passwordFlag
}
return &cfg

View File

@ -47,6 +47,7 @@ func NewUserCommand() *cobra.Command {
var (
passwordInteractive bool
passwordFromFlag string
)
func newUserAddCommand() *cobra.Command {
@ -57,6 +58,7 @@ func newUserAddCommand() *cobra.Command {
}
cmd.Flags().BoolVar(&passwordInteractive, "interactive", true, "Read password from stdin instead of interactive terminal")
cmd.Flags().StringVar(&passwordFromFlag, "new-user-password", "", "Supply password from the command line flag")
return &cmd
}
@ -126,19 +128,24 @@ func userAddCommandFunc(cmd *cobra.Command, args []string) {
var password string
var user string
splitted := strings.SplitN(args[0], ":", 2)
if len(splitted) < 2 {
if passwordFromFlag != "" {
user = args[0]
if !passwordInteractive {
fmt.Scanf("%s", &password)
} else {
password = readPasswordInteractive(args[0])
}
password = passwordFromFlag
} else {
user = splitted[0]
password = splitted[1]
if len(user) == 0 {
ExitWithError(ExitBadArgs, fmt.Errorf("empty user name is not allowed."))
splitted := strings.SplitN(args[0], ":", 2)
if len(splitted) < 2 {
user = args[0]
if !passwordInteractive {
fmt.Scanf("%s", &password)
} else {
password = readPasswordInteractive(args[0])
}
} else {
user = splitted[0]
password = splitted[1]
if len(user) == 0 {
ExitWithError(ExitBadArgs, fmt.Errorf("empty user name is not allowed."))
}
}
}

View File

@ -65,6 +65,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&globalFlags.TLS.KeyFile, "key", "", "identify secure client using this TLS key file")
rootCmd.PersistentFlags().StringVar(&globalFlags.TLS.TrustedCAFile, "cacert", "", "verify certificates of TLS-enabled secure servers using this CA bundle")
rootCmd.PersistentFlags().StringVar(&globalFlags.User, "user", "", "username[:password] for authentication (prompt if password is not supplied)")
rootCmd.PersistentFlags().StringVar(&globalFlags.Password, "password", "", "password for authentication (if this option is used, --user option shouldn't include password)")
rootCmd.PersistentFlags().StringVarP(&globalFlags.TLS.ServerName, "discovery-srv", "d", "", "domain name to query for SRV records describing cluster endpoints")
rootCmd.AddCommand(