2015-03-25 03:57:23 +00:00
package client
import (
"bufio"
"fmt"
"io"
"os"
2015-11-05 22:19:48 +00:00
"runtime"
2015-03-25 03:57:23 +00:00
"strings"
2016-03-16 19:19:22 +00:00
"golang.org/x/net/context"
2015-05-05 04:18:28 +00:00
Cli "github.com/docker/docker/cli"
2016-04-21 22:37:08 +00:00
"github.com/docker/docker/cliconfig/configfile"
2016-02-08 00:55:17 +00:00
"github.com/docker/docker/cliconfig/credentials"
2015-03-25 03:57:23 +00:00
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/term"
2016-01-05 00:05:26 +00:00
"github.com/docker/engine-api/types"
2015-03-25 03:57:23 +00:00
)
2016-03-01 01:51:36 +00:00
// CmdLogin logs in a user to a Docker registry service.
2015-03-25 17:34:41 +00:00
//
// If no server is specified, the user will be logged into or registered to the registry's index server.
//
// Usage: docker login SERVER
2015-03-25 03:57:23 +00:00
func ( cli * DockerCli ) CmdLogin ( args ... string ) error {
2016-02-01 19:13:11 +00:00
cmd := Cli . Subcmd ( "login" , [ ] string { "[SERVER]" } , Cli . DockerCommands [ "login" ] . Description + ".\nIf no server is specified, the default is defined by the daemon." , true )
2015-03-25 03:57:23 +00:00
cmd . Require ( flag . Max , 1 )
2016-01-27 23:26:48 +00:00
flUser := cmd . String ( [ ] string { "u" , "-username" } , "" , "Username" )
flPassword := cmd . String ( [ ] string { "p" , "-password" } , "" , "Password" )
2016-03-01 01:51:36 +00:00
// Deprecated in 1.11: Should be removed in docker 1.13
cmd . String ( [ ] string { "#e" , "#-email" } , "" , "Email" )
2015-03-25 03:57:23 +00:00
2015-03-29 01:22:46 +00:00
cmd . ParseFlags ( args , true )
2015-03-25 03:57:23 +00:00
2015-11-05 22:19:48 +00:00
// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
if runtime . GOOS == "windows" {
cli . in = os . Stdin
}
2016-02-03 18:30:17 +00:00
var serverAddress string
2016-03-01 01:51:36 +00:00
var isDefaultRegistry bool
2015-03-25 03:57:23 +00:00
if len ( cmd . Args ( ) ) > 0 {
serverAddress = cmd . Arg ( 0 )
2016-02-03 18:30:17 +00:00
} else {
serverAddress = cli . electAuthServer ( )
2016-03-01 01:51:36 +00:00
isDefaultRegistry = true
2015-03-25 03:57:23 +00:00
}
2016-03-01 01:51:36 +00:00
authConfig , err := cli . configureAuth ( * flUser , * flPassword , serverAddress , isDefaultRegistry )
2016-01-27 23:26:48 +00:00
if err != nil {
return err
2015-03-25 03:57:23 +00:00
}
2016-03-16 19:19:22 +00:00
response , err := cli . client . RegistryLogin ( context . Background ( ) , authConfig )
2016-01-27 23:26:48 +00:00
if err != nil {
return err
2015-03-25 03:57:23 +00:00
}
2016-02-24 00:29:16 +00:00
if response . IdentityToken != "" {
authConfig . Password = ""
authConfig . IdentityToken = response . IdentityToken
}
2016-02-08 00:55:17 +00:00
if err := storeCredentials ( cli . configFile , authConfig ) ; err != nil {
return fmt . Errorf ( "Error saving credentials: %v" , err )
2016-01-27 23:26:48 +00:00
}
if response . Status != "" {
2016-02-24 00:29:16 +00:00
fmt . Fprintln ( cli . out , response . Status )
2016-01-27 23:26:48 +00:00
}
return nil
}
func ( cli * DockerCli ) promptWithDefault ( prompt string , configDefault string ) {
if configDefault == "" {
fmt . Fprintf ( cli . out , "%s: " , prompt )
} else {
fmt . Fprintf ( cli . out , "%s (%s): " , prompt , configDefault )
}
}
2016-03-01 01:51:36 +00:00
func ( cli * DockerCli ) configureAuth ( flUser , flPassword , serverAddress string , isDefaultRegistry bool ) ( types . AuthConfig , error ) {
2016-02-08 00:55:17 +00:00
authconfig , err := getCredentials ( cli . configFile , serverAddress )
if err != nil {
return authconfig , err
2015-03-25 03:57:23 +00:00
}
2016-02-08 00:55:17 +00:00
2016-01-28 14:17:28 +00:00
authconfig . Username = strings . TrimSpace ( authconfig . Username )
2015-03-25 03:57:23 +00:00
2016-01-28 14:17:28 +00:00
if flUser = strings . TrimSpace ( flUser ) ; flUser == "" {
2016-03-01 01:51:36 +00:00
if isDefaultRegistry {
// if this is a defauly registry (docker hub), then display the following message.
fmt . Fprintln ( cli . out , "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one." )
}
2016-01-27 23:26:48 +00:00
cli . promptWithDefault ( "Username" , authconfig . Username )
flUser = readInput ( cli . in , cli . out )
flUser = strings . TrimSpace ( flUser )
if flUser == "" {
flUser = authconfig . Username
2015-03-25 03:57:23 +00:00
}
}
2016-01-28 14:17:28 +00:00
if flUser == "" {
return authconfig , fmt . Errorf ( "Error: Non-null Username Required" )
}
2016-01-27 23:26:48 +00:00
if flPassword == "" {
oldState , err := term . SaveState ( cli . inFd )
if err != nil {
return authconfig , err
}
fmt . Fprintf ( cli . out , "Password: " )
term . DisableEcho ( cli . inFd , oldState )
2015-03-25 03:57:23 +00:00
2016-01-27 23:26:48 +00:00
flPassword = readInput ( cli . in , cli . out )
fmt . Fprint ( cli . out , "\n" )
term . RestoreTerminal ( cli . inFd , oldState )
if flPassword == "" {
2016-01-28 14:17:28 +00:00
return authconfig , fmt . Errorf ( "Error: Password Required" )
2015-03-25 03:57:23 +00:00
}
2016-01-27 23:26:48 +00:00
}
2015-03-25 03:57:23 +00:00
2016-01-27 23:26:48 +00:00
authconfig . Username = flUser
authconfig . Password = flPassword
2015-03-25 03:57:23 +00:00
authconfig . ServerAddress = serverAddress
2016-02-24 00:29:16 +00:00
authconfig . IdentityToken = ""
2016-02-08 00:55:17 +00:00
2016-01-27 23:26:48 +00:00
return authconfig , nil
}
2015-03-25 03:57:23 +00:00
2016-01-27 23:26:48 +00:00
func readInput ( in io . Reader , out io . Writer ) string {
reader := bufio . NewReader ( in )
line , _ , err := reader . ReadLine ( )
2015-03-25 03:57:23 +00:00
if err != nil {
2016-01-27 23:26:48 +00:00
fmt . Fprintln ( out , err . Error ( ) )
os . Exit ( 1 )
2015-04-01 22:39:37 +00:00
}
2016-01-27 23:26:48 +00:00
return string ( line )
2015-03-25 03:57:23 +00:00
}
2016-02-08 00:55:17 +00:00
// getCredentials loads the user credentials from a credentials store.
// The store is determined by the config file settings.
2016-04-21 22:37:08 +00:00
func getCredentials ( c * configfile . ConfigFile , serverAddress string ) ( types . AuthConfig , error ) {
2016-02-08 00:55:17 +00:00
s := loadCredentialsStore ( c )
return s . Get ( serverAddress )
}
2016-04-21 22:37:08 +00:00
func getAllCredentials ( c * configfile . ConfigFile ) ( map [ string ] types . AuthConfig , error ) {
2016-03-01 17:04:35 +00:00
s := loadCredentialsStore ( c )
return s . GetAll ( )
}
2016-02-08 00:55:17 +00:00
// storeCredentials saves the user credentials in a credentials store.
// The store is determined by the config file settings.
2016-04-21 22:37:08 +00:00
func storeCredentials ( c * configfile . ConfigFile , auth types . AuthConfig ) error {
2016-02-08 00:55:17 +00:00
s := loadCredentialsStore ( c )
return s . Store ( auth )
}
// eraseCredentials removes the user credentials from a credentials store.
// The store is determined by the config file settings.
2016-04-21 22:37:08 +00:00
func eraseCredentials ( c * configfile . ConfigFile , serverAddress string ) error {
2016-02-08 00:55:17 +00:00
s := loadCredentialsStore ( c )
return s . Erase ( serverAddress )
}
// loadCredentialsStore initializes a new credentials store based
// in the settings provided in the configuration file.
2016-04-21 22:37:08 +00:00
func loadCredentialsStore ( c * configfile . ConfigFile ) credentials . Store {
2016-02-08 00:55:17 +00:00
if c . CredentialsStore != "" {
return credentials . NewNativeStore ( c )
}
return credentials . NewFileStore ( c )
}