Skip to content

Commit 1d1562e

Browse files
authored
Merge pull request #7029 from agirault/login-password-dash-stdin
cli/registry: support password dash stdin
2 parents 8c2e800 + 450df79 commit 1d1562e

3 files changed

Lines changed: 94 additions & 9 deletions

File tree

cli/command/registry/login.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func newLoginCommand(dockerCLI command.Cli) *cobra.Command {
6262
flags := cmd.Flags()
6363

6464
flags.StringVarP(&opts.user, "username", "u", "", "Username")
65-
flags.StringVarP(&opts.password, "password", "p", "", "Password or Personal Access Token (PAT)")
65+
flags.StringVarP(&opts.password, "password", "p", "", `Password or Personal Access Token (PAT), or "-" to read from stdin`)
6666
flags.BoolVar(&opts.passwordStdin, "password-stdin", false, "Take the Password or Personal Access Token (PAT) from stdin")
6767

6868
return cmd
@@ -72,8 +72,8 @@ func newLoginCommand(dockerCLI command.Cli) *cobra.Command {
7272
//
7373
// TODO(thaJeztah); combine with verifyLoginOptions, but this requires rewrites of many tests.
7474
func verifyLoginFlags(flags *pflag.FlagSet, opts loginOptions) error {
75-
if flags.Changed("password-stdin") {
76-
if flags.Changed("password") {
75+
if flags.Changed("password-stdin") || opts.password == "-" {
76+
if flags.Changed("password") && opts.password != "-" {
7777
return errors.New("conflicting options: cannot specify both --password and --password-stdin")
7878
}
7979
if !flags.Changed("username") {
@@ -122,6 +122,11 @@ func readSecretFromStdin(r io.Reader) (string, error) {
122122
}
123123

124124
func verifyLoginOptions(dockerCLI command.Streams, opts *loginOptions) error {
125+
if opts.password == "-" {
126+
opts.password = ""
127+
opts.passwordStdin = true
128+
}
129+
125130
if opts.password != "" {
126131
_, _ = fmt.Fprintln(dockerCLI.Err(), "WARNING! Using --password via the CLI is insecure. Use --password-stdin.")
127132
}

cli/command/registry/login_test.go

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,57 @@ func TestRunLogin(t *testing.T) {
339339
},
340340
},
341341
},
342+
{
343+
doc: "password dash reads password from stdin",
344+
priorCredentials: map[string]configtypes.AuthConfig{},
345+
stdIn: "my password\r\n",
346+
input: loginOptions{
347+
serverAddress: "reg1",
348+
user: "my-username",
349+
password: "-",
350+
},
351+
expectedCredentials: map[string]configtypes.AuthConfig{
352+
"reg1": {
353+
Username: "my-username",
354+
Password: "my password",
355+
ServerAddress: "reg1",
356+
},
357+
},
358+
},
359+
{
360+
doc: "password dash empty stdin",
361+
priorCredentials: map[string]configtypes.AuthConfig{},
362+
input: loginOptions{
363+
serverAddress: "reg1",
364+
user: "my-username",
365+
password: "-",
366+
},
367+
expectedErr: `password is empty`,
368+
expectedCredentials: map[string]configtypes.AuthConfig{
369+
"reg1": {
370+
Username: "my-username",
371+
ServerAddress: "reg1",
372+
},
373+
},
374+
},
375+
{
376+
doc: "password dash and password stdin read password from stdin",
377+
priorCredentials: map[string]configtypes.AuthConfig{},
378+
stdIn: "my password\r\n",
379+
input: loginOptions{
380+
serverAddress: "reg1",
381+
user: "my-username",
382+
password: "-",
383+
passwordStdin: true,
384+
},
385+
expectedCredentials: map[string]configtypes.AuthConfig{
386+
"reg1": {
387+
Username: "my-username",
388+
Password: "my password",
389+
ServerAddress: "reg1",
390+
},
391+
},
392+
},
342393
{
343394
doc: "password with leading and trailing spaces",
344395
priorCredentials: map[string]configtypes.AuthConfig{},
@@ -397,7 +448,7 @@ func TestRunLogin(t *testing.T) {
397448
cfg := configfile.New(filepath.Join(tmpDir, "config.json"))
398449
cli := test.NewFakeCli(&fakeClient{})
399450
cli.SetConfigFile(cfg)
400-
if tc.input.passwordStdin {
451+
if tc.input.passwordStdin || tc.input.password == "-" || tc.stdIn != "" {
401452
if tc.expectedErr == "TEST_READ_ERR" {
402453
cli.SetIn(streams.NewIn(io.NopCloser(iotest.ErrReader(errors.New(tc.expectedErr)))))
403454
} else {
@@ -632,6 +683,21 @@ func TestLoginValidateFlags(t *testing.T) {
632683
args: []string{"--password-stdin", "--password", ""},
633684
expectedErr: `conflicting options: cannot specify both --password and --password-stdin`,
634685
},
686+
{
687+
name: "password stdin and password dash without stdin",
688+
args: []string{"--password-stdin", "--username", "my-username", "--password", "-"},
689+
expectedErr: `password is empty`,
690+
},
691+
{
692+
name: "password dash without username",
693+
args: []string{"--password", "-"},
694+
expectedErr: `the --password-stdin option requires --username to be set`,
695+
},
696+
{
697+
name: "short password dash without username",
698+
args: []string{"-p", "-"},
699+
expectedErr: `the --password-stdin option requires --username to be set`,
700+
},
635701
{
636702
name: "empty --password",
637703
args: []string{"--password", ""},
@@ -658,3 +724,10 @@ func TestLoginValidateFlags(t *testing.T) {
658724
})
659725
}
660726
}
727+
728+
func TestLoginHelpDocumentsPasswordDash(t *testing.T) {
729+
cmd := newLoginCommand(test.NewFakeCli(&fakeClient{}))
730+
flag := cmd.Flags().Lookup("password")
731+
assert.Check(t, flag != nil)
732+
assert.Check(t, is.Contains(flag.Usage, `"-"`))
733+
}

docs/reference/commandline/login.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ Defaults to Docker Hub if no server is specified.
66

77
### Options
88

9-
| Name | Type | Default | Description |
10-
|:---------------------------------------------|:---------|:--------|:------------------------------------------------------------|
11-
| `-p`, `--password` | `string` | | Password or Personal Access Token (PAT) |
12-
| [`--password-stdin`](#password-stdin) | `bool` | | Take the Password or Personal Access Token (PAT) from stdin |
13-
| [`-u`](#username), [`--username`](#username) | `string` | | Username |
9+
| Name | Type | Default | Description |
10+
|:---------------------------------------------|:---------|:--------|:-------------------------------------------------------------------|
11+
| `-p`, `--password` | `string` | | Password or Personal Access Token (PAT), or `-` to read from stdin |
12+
| [`--password-stdin`](#password-stdin) | `bool` | | Take the Password or Personal Access Token (PAT) from stdin |
13+
| [`-u`](#username), [`--username`](#username) | `string` | | Username |
1414

1515

1616
<!---MARKER_GEN_END-->
@@ -244,6 +244,13 @@ The following example reads a password from a file, and passes it to the
244244
$ cat ~/my_password.txt | docker login --username foo --password-stdin
245245
```
246246

247+
You can also pass `-` as the value for `--password` or `-p` to read the
248+
password from `STDIN`.
249+
250+
```console
251+
$ cat ~/my_password.txt | docker login --username foo --password -
252+
```
253+
247254
## Related commands
248255

249256
* [logout](logout.md)

0 commit comments

Comments
 (0)