mirror of
https://github.com/docker/cli.git
synced 2026-08-24 10:05:37 -05:00
cli/registry: support password dash stdin
Signed-off-by: Alexis Girault <agirault@nvidia.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
@@ -62,7 +62,7 @@ func newLoginCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
flags := cmd.Flags()
|
||||
|
||||
flags.StringVarP(&opts.user, "username", "u", "", "Username")
|
||||
flags.StringVarP(&opts.password, "password", "p", "", "Password or Personal Access Token (PAT)")
|
||||
flags.StringVarP(&opts.password, "password", "p", "", `Password or Personal Access Token (PAT), or "-" to read from stdin`)
|
||||
flags.BoolVar(&opts.passwordStdin, "password-stdin", false, "Take the Password or Personal Access Token (PAT) from stdin")
|
||||
|
||||
return cmd
|
||||
@@ -72,8 +72,8 @@ func newLoginCommand(dockerCLI command.Cli) *cobra.Command {
|
||||
//
|
||||
// TODO(thaJeztah); combine with verifyLoginOptions, but this requires rewrites of many tests.
|
||||
func verifyLoginFlags(flags *pflag.FlagSet, opts loginOptions) error {
|
||||
if flags.Changed("password-stdin") {
|
||||
if flags.Changed("password") {
|
||||
if flags.Changed("password-stdin") || opts.password == "-" {
|
||||
if flags.Changed("password") && opts.password != "-" {
|
||||
return errors.New("conflicting options: cannot specify both --password and --password-stdin")
|
||||
}
|
||||
if !flags.Changed("username") {
|
||||
@@ -122,6 +122,11 @@ func readSecretFromStdin(r io.Reader) (string, error) {
|
||||
}
|
||||
|
||||
func verifyLoginOptions(dockerCLI command.Streams, opts *loginOptions) error {
|
||||
if opts.password == "-" {
|
||||
opts.password = ""
|
||||
opts.passwordStdin = true
|
||||
}
|
||||
|
||||
if opts.password != "" {
|
||||
_, _ = fmt.Fprintln(dockerCLI.Err(), "WARNING! Using --password via the CLI is insecure. Use --password-stdin.")
|
||||
}
|
||||
|
||||
@@ -339,6 +339,57 @@ func TestRunLogin(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "password dash reads password from stdin",
|
||||
priorCredentials: map[string]configtypes.AuthConfig{},
|
||||
stdIn: "my password\r\n",
|
||||
input: loginOptions{
|
||||
serverAddress: "reg1",
|
||||
user: "my-username",
|
||||
password: "-",
|
||||
},
|
||||
expectedCredentials: map[string]configtypes.AuthConfig{
|
||||
"reg1": {
|
||||
Username: "my-username",
|
||||
Password: "my password",
|
||||
ServerAddress: "reg1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "password dash empty stdin",
|
||||
priorCredentials: map[string]configtypes.AuthConfig{},
|
||||
input: loginOptions{
|
||||
serverAddress: "reg1",
|
||||
user: "my-username",
|
||||
password: "-",
|
||||
},
|
||||
expectedErr: `password is empty`,
|
||||
expectedCredentials: map[string]configtypes.AuthConfig{
|
||||
"reg1": {
|
||||
Username: "my-username",
|
||||
ServerAddress: "reg1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "password dash and password stdin read password from stdin",
|
||||
priorCredentials: map[string]configtypes.AuthConfig{},
|
||||
stdIn: "my password\r\n",
|
||||
input: loginOptions{
|
||||
serverAddress: "reg1",
|
||||
user: "my-username",
|
||||
password: "-",
|
||||
passwordStdin: true,
|
||||
},
|
||||
expectedCredentials: map[string]configtypes.AuthConfig{
|
||||
"reg1": {
|
||||
Username: "my-username",
|
||||
Password: "my password",
|
||||
ServerAddress: "reg1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "password with leading and trailing spaces",
|
||||
priorCredentials: map[string]configtypes.AuthConfig{},
|
||||
@@ -397,7 +448,7 @@ func TestRunLogin(t *testing.T) {
|
||||
cfg := configfile.New(filepath.Join(tmpDir, "config.json"))
|
||||
cli := test.NewFakeCli(&fakeClient{})
|
||||
cli.SetConfigFile(cfg)
|
||||
if tc.input.passwordStdin {
|
||||
if tc.input.passwordStdin || tc.input.password == "-" || tc.stdIn != "" {
|
||||
if tc.expectedErr == "TEST_READ_ERR" {
|
||||
cli.SetIn(streams.NewIn(io.NopCloser(iotest.ErrReader(errors.New(tc.expectedErr)))))
|
||||
} else {
|
||||
@@ -632,6 +683,21 @@ func TestLoginValidateFlags(t *testing.T) {
|
||||
args: []string{"--password-stdin", "--password", ""},
|
||||
expectedErr: `conflicting options: cannot specify both --password and --password-stdin`,
|
||||
},
|
||||
{
|
||||
name: "password stdin and password dash without stdin",
|
||||
args: []string{"--password-stdin", "--username", "my-username", "--password", "-"},
|
||||
expectedErr: `password is empty`,
|
||||
},
|
||||
{
|
||||
name: "password dash without username",
|
||||
args: []string{"--password", "-"},
|
||||
expectedErr: `the --password-stdin option requires --username to be set`,
|
||||
},
|
||||
{
|
||||
name: "short password dash without username",
|
||||
args: []string{"-p", "-"},
|
||||
expectedErr: `the --password-stdin option requires --username to be set`,
|
||||
},
|
||||
{
|
||||
name: "empty --password",
|
||||
args: []string{"--password", ""},
|
||||
@@ -658,3 +724,10 @@ func TestLoginValidateFlags(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginHelpDocumentsPasswordDash(t *testing.T) {
|
||||
cmd := newLoginCommand(test.NewFakeCli(&fakeClient{}))
|
||||
flag := cmd.Flags().Lookup("password")
|
||||
assert.Check(t, flag != nil)
|
||||
assert.Check(t, is.Contains(flag.Usage, `"-"`))
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ Defaults to Docker Hub if no server is specified.
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|:---------------------------------------------|:---------|:--------|:------------------------------------------------------------|
|
||||
| `-p`, `--password` | `string` | | Password or Personal Access Token (PAT) |
|
||||
| [`--password-stdin`](#password-stdin) | `bool` | | Take the Password or Personal Access Token (PAT) from stdin |
|
||||
| [`-u`](#username), [`--username`](#username) | `string` | | Username |
|
||||
| Name | Type | Default | Description |
|
||||
|:---------------------------------------------|:---------|:--------|:-------------------------------------------------------------------|
|
||||
| `-p`, `--password` | `string` | | Password or Personal Access Token (PAT), or `-` to read from stdin |
|
||||
| [`--password-stdin`](#password-stdin) | `bool` | | Take the Password or Personal Access Token (PAT) from stdin |
|
||||
| [`-u`](#username), [`--username`](#username) | `string` | | Username |
|
||||
|
||||
|
||||
<!---MARKER_GEN_END-->
|
||||
@@ -244,6 +244,13 @@ The following example reads a password from a file, and passes it to the
|
||||
$ cat ~/my_password.txt | docker login --username foo --password-stdin
|
||||
```
|
||||
|
||||
You can also pass `-` as the value for `--password` or `-p` to read the
|
||||
password from `STDIN`.
|
||||
|
||||
```console
|
||||
$ cat ~/my_password.txt | docker login --username foo --password -
|
||||
```
|
||||
|
||||
## Related commands
|
||||
|
||||
* [logout](logout.md)
|
||||
|
||||
Reference in New Issue
Block a user