@@ -14,6 +14,7 @@ import (
1414 "github.com/docker/cli/cli/config/configfile"
1515 configtypes "github.com/docker/cli/cli/config/types"
1616 "github.com/docker/cli/cli/internal/oauth/manager"
17+ "github.com/docker/cli/internal/tui"
1718 registrytypes "github.com/docker/docker/api/types/registry"
1819 "github.com/docker/docker/client"
1920 "github.com/docker/docker/errdefs"
@@ -30,7 +31,7 @@ type loginOptions struct {
3031}
3132
3233// NewLoginCommand creates a new `docker login` command
33- func NewLoginCommand (dockerCli command.Cli ) * cobra.Command {
34+ func NewLoginCommand (dockerCLI command.Cli ) * cobra.Command {
3435 var opts loginOptions
3536
3637 cmd := & cobra.Command {
@@ -42,7 +43,7 @@ func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
4243 if len (args ) > 0 {
4344 opts .serverAddress = args [0 ]
4445 }
45- return runLogin (cmd .Context (), dockerCli , opts )
46+ return runLogin (cmd .Context (), dockerCLI , opts )
4647 },
4748 Annotations : map [string ]string {
4849 "category-top" : "8" ,
@@ -53,15 +54,15 @@ func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
5354 flags := cmd .Flags ()
5455
5556 flags .StringVarP (& opts .user , "username" , "u" , "" , "Username" )
56- flags .StringVarP (& opts .password , "password" , "p" , "" , "Password" )
57- flags .BoolVar (& opts .passwordStdin , "password-stdin" , false , "Take the password from stdin" )
57+ flags .StringVarP (& opts .password , "password" , "p" , "" , "Password or Personal Access Token (PAT) " )
58+ flags .BoolVar (& opts .passwordStdin , "password-stdin" , false , "Take the Password or Personal Access Token (PAT) from stdin" )
5859
5960 return cmd
6061}
6162
62- func verifyLoginOptions (dockerCli command.Cli , opts * loginOptions ) error {
63+ func verifyLoginOptions (dockerCLI command.Cli , opts * loginOptions ) error {
6364 if opts .password != "" {
64- _ , _ = fmt .Fprintln (dockerCli .Err (), "WARNING! Using --password via the CLI is insecure. Use --password-stdin." )
65+ _ , _ = fmt .Fprintln (dockerCLI .Err (), "WARNING! Using --password via the CLI is insecure. Use --password-stdin." )
6566 if opts .passwordStdin {
6667 return errors .New ("--password and --password-stdin are mutually exclusive" )
6768 }
@@ -72,7 +73,7 @@ func verifyLoginOptions(dockerCli command.Cli, opts *loginOptions) error {
7273 return errors .New ("Must provide --username with --password-stdin" )
7374 }
7475
75- contents , err := io .ReadAll (dockerCli .In ())
76+ contents , err := io .ReadAll (dockerCLI .In ())
7677 if err != nil {
7778 return err
7879 }
@@ -83,8 +84,8 @@ func verifyLoginOptions(dockerCli command.Cli, opts *loginOptions) error {
8384 return nil
8485}
8586
86- func runLogin (ctx context.Context , dockerCli command.Cli , opts loginOptions ) error {
87- if err := verifyLoginOptions (dockerCli , & opts ); err != nil {
87+ func runLogin (ctx context.Context , dockerCLI command.Cli , opts loginOptions ) error {
88+ if err := verifyLoginOptions (dockerCLI , & opts ); err != nil {
8889 return err
8990 }
9091 var (
@@ -99,28 +100,38 @@ func runLogin(ctx context.Context, dockerCli command.Cli, opts loginOptions) err
99100 isDefaultRegistry := serverAddress == registry .IndexServer
100101
101102 // attempt login with current (stored) credentials
102- authConfig , err := command .GetDefaultAuthConfig (dockerCli .ConfigFile (), opts .user == "" && opts .password == "" , serverAddress , isDefaultRegistry )
103+ authConfig , err := command .GetDefaultAuthConfig (dockerCLI .ConfigFile (), opts .user == "" && opts .password == "" , serverAddress , isDefaultRegistry )
103104 if err == nil && authConfig .Username != "" && authConfig .Password != "" {
104- msg , err = loginWithStoredCredentials (ctx , dockerCli , authConfig )
105+ msg , err = loginWithStoredCredentials (ctx , dockerCLI , authConfig )
105106 }
106107
107108 // if we failed to authenticate with stored credentials (or didn't have stored credentials),
108109 // prompt the user for new credentials
109110 if err != nil || authConfig .Username == "" || authConfig .Password == "" {
110- msg , err = loginUser (ctx , dockerCli , opts , authConfig .Username , authConfig .ServerAddress )
111+ msg , err = loginUser (ctx , dockerCLI , opts , authConfig .Username , authConfig .ServerAddress )
111112 if err != nil {
112113 return err
113114 }
114115 }
115116
116117 if msg != "" {
117- _ , _ = fmt .Fprintln (dockerCli .Out (), msg )
118+ _ , _ = fmt .Fprintln (dockerCLI .Out (), msg )
118119 }
119120 return nil
120121}
121122
122123func loginWithStoredCredentials (ctx context.Context , dockerCLI command.Cli , authConfig registrytypes.AuthConfig ) (msg string , _ error ) {
123- _ , _ = fmt .Fprintln (dockerCLI .Out (), "Authenticating with existing credentials..." )
124+ _ , _ = fmt .Fprintf (dockerCLI .Err (), "Authenticating with existing credentials..." )
125+ if authConfig .Username != "" {
126+ _ , _ = fmt .Fprintf (dockerCLI .Err (), " [Username: %s]" , authConfig .Username )
127+ }
128+ _ , _ = fmt .Fprint (dockerCLI .Err (), "\n " )
129+
130+ out := tui .NewOutput (dockerCLI .Err ())
131+ out .PrintNote ("To login with a different account, run 'docker logout' followed by 'docker login'" )
132+
133+ _ , _ = fmt .Fprint (dockerCLI .Err (), "\n \n " )
134+
124135 response , err := dockerCLI .Client ().RegistryLogin (ctx , authConfig )
125136 if err != nil {
126137 if errdefs .IsUnauthorized (err ) {
@@ -155,41 +166,41 @@ func isOauthLoginDisabled() bool {
155166 return false
156167}
157168
158- func loginUser (ctx context.Context , dockerCli command.Cli , opts loginOptions , defaultUsername , serverAddress string ) (msg string , _ error ) {
169+ func loginUser (ctx context.Context , dockerCLI command.Cli , opts loginOptions , defaultUsername , serverAddress string ) (msg string , _ error ) {
159170 // Some links documenting this:
160171 // - https://code.google.com/archive/p/mintty/issues/56
161172 // - https://github.com/docker/docker/issues/15272
162173 // - https://mintty.github.io/ (compatibility)
163174 // Linux will hit this if you attempt `cat | docker login`, and Windows
164175 // will hit this if you attempt docker login from mintty where stdin
165176 // is a pipe, not a character based console.
166- if (opts .user == "" || opts .password == "" ) && ! dockerCli .In ().IsTerminal () {
177+ if (opts .user == "" || opts .password == "" ) && ! dockerCLI .In ().IsTerminal () {
167178 return "" , errors .Errorf ("Error: Cannot perform an interactive login from a non TTY device" )
168179 }
169180
170181 // If we're logging into the index server and the user didn't provide a username or password, use the device flow
171182 if serverAddress == registry .IndexServer && opts .user == "" && opts .password == "" && ! isOauthLoginDisabled () {
172183 var err error
173- msg , err = loginWithDeviceCodeFlow (ctx , dockerCli )
184+ msg , err = loginWithDeviceCodeFlow (ctx , dockerCLI )
174185 // if the error represents a failure to initiate the device-code flow,
175186 // then we fallback to regular cli credentials login
176187 if ! errors .Is (err , manager .ErrDeviceLoginStartFail ) {
177188 return msg , err
178189 }
179- _ , _ = fmt .Fprint (dockerCli .Err (), "Failed to start web-based login - falling back to command line login...\n \n " )
190+ _ , _ = fmt .Fprint (dockerCLI .Err (), "Failed to start web-based login - falling back to command line login...\n \n " )
180191 }
181192
182- return loginWithUsernameAndPassword (ctx , dockerCli , opts , defaultUsername , serverAddress )
193+ return loginWithUsernameAndPassword (ctx , dockerCLI , opts , defaultUsername , serverAddress )
183194}
184195
185- func loginWithUsernameAndPassword (ctx context.Context , dockerCli command.Cli , opts loginOptions , defaultUsername , serverAddress string ) (msg string , _ error ) {
196+ func loginWithUsernameAndPassword (ctx context.Context , dockerCLI command.Cli , opts loginOptions , defaultUsername , serverAddress string ) (msg string , _ error ) {
186197 // Prompt user for credentials
187- authConfig , err := command .PromptUserForCredentials (ctx , dockerCli , opts .user , opts .password , defaultUsername , serverAddress )
198+ authConfig , err := command .PromptUserForCredentials (ctx , dockerCLI , opts .user , opts .password , defaultUsername , serverAddress )
188199 if err != nil {
189200 return "" , err
190201 }
191202
192- response , err := loginWithRegistry (ctx , dockerCli .Client (), authConfig )
203+ response , err := loginWithRegistry (ctx , dockerCLI .Client (), authConfig )
193204 if err != nil {
194205 return "" , err
195206 }
@@ -198,26 +209,26 @@ func loginWithUsernameAndPassword(ctx context.Context, dockerCli command.Cli, op
198209 authConfig .Password = ""
199210 authConfig .IdentityToken = response .IdentityToken
200211 }
201- if err = storeCredentials (dockerCli .ConfigFile (), authConfig ); err != nil {
212+ if err = storeCredentials (dockerCLI .ConfigFile (), authConfig ); err != nil {
202213 return "" , err
203214 }
204215
205216 return response .Status , nil
206217}
207218
208- func loginWithDeviceCodeFlow (ctx context.Context , dockerCli command.Cli ) (msg string , _ error ) {
209- store := dockerCli .ConfigFile ().GetCredentialsStore (registry .IndexServer )
210- authConfig , err := manager .NewManager (store ).LoginDevice (ctx , dockerCli .Err ())
219+ func loginWithDeviceCodeFlow (ctx context.Context , dockerCLI command.Cli ) (msg string , _ error ) {
220+ store := dockerCLI .ConfigFile ().GetCredentialsStore (registry .IndexServer )
221+ authConfig , err := manager .NewManager (store ).LoginDevice (ctx , dockerCLI .Err ())
211222 if err != nil {
212223 return "" , err
213224 }
214225
215- response , err := loginWithRegistry (ctx , dockerCli .Client (), registrytypes .AuthConfig (* authConfig ))
226+ response , err := loginWithRegistry (ctx , dockerCLI .Client (), registrytypes .AuthConfig (* authConfig ))
216227 if err != nil {
217228 return "" , err
218229 }
219230
220- if err = storeCredentials (dockerCli .ConfigFile (), registrytypes .AuthConfig (* authConfig )); err != nil {
231+ if err = storeCredentials (dockerCLI .ConfigFile (), registrytypes .AuthConfig (* authConfig )); err != nil {
221232 return "" , err
222233 }
223234
0 commit comments