123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- package client
- import (
- "bufio"
- "fmt"
- "io"
- "os"
- "runtime"
- "strings"
- "golang.org/x/net/context"
- Cli "github.com/docker/docker/cli"
- "github.com/docker/docker/cliconfig/configfile"
- "github.com/docker/docker/cliconfig/credentials"
- flag "github.com/docker/docker/pkg/mflag"
- "github.com/docker/docker/pkg/term"
- "github.com/docker/engine-api/types"
- )
- // CmdLogin logs in a user to a Docker registry service.
- //
- // If no server is specified, the user will be logged into or registered to the registry's index server.
- //
- // Usage: docker login SERVER
- func (cli *DockerCli) CmdLogin(args ...string) error {
- cmd := Cli.Subcmd("login", []string{"[SERVER]"}, Cli.DockerCommands["login"].Description+".\nIf no server is specified, the default is defined by the daemon.", true)
- cmd.Require(flag.Max, 1)
- flUser := cmd.String([]string{"u", "-username"}, "", "Username")
- flPassword := cmd.String([]string{"p", "-password"}, "", "Password")
- // Deprecated in 1.11: Should be removed in docker 1.13
- cmd.String([]string{"#e", "#-email"}, "", "Email")
- cmd.ParseFlags(args, true)
- // On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
- if runtime.GOOS == "windows" {
- cli.in = os.Stdin
- }
- ctx := context.Background()
- var serverAddress string
- var isDefaultRegistry bool
- if len(cmd.Args()) > 0 {
- serverAddress = cmd.Arg(0)
- } else {
- serverAddress = cli.electAuthServer(ctx)
- isDefaultRegistry = true
- }
- authConfig, err := cli.configureAuth(*flUser, *flPassword, serverAddress, isDefaultRegistry)
- if err != nil {
- return err
- }
- response, err := cli.client.RegistryLogin(ctx, authConfig)
- if err != nil {
- return err
- }
- if response.IdentityToken != "" {
- authConfig.Password = ""
- authConfig.IdentityToken = response.IdentityToken
- }
- if err := storeCredentials(cli.configFile, authConfig); err != nil {
- return fmt.Errorf("Error saving credentials: %v", err)
- }
- if response.Status != "" {
- fmt.Fprintln(cli.out, response.Status)
- }
- 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)
- }
- }
- func (cli *DockerCli) configureAuth(flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) {
- authconfig, err := getCredentials(cli.configFile, serverAddress)
- if err != nil {
- return authconfig, err
- }
- // Some links documenting this:
- // - https://code.google.com/archive/p/mintty/issues/56
- // - https://github.com/docker/docker/issues/15272
- // - https://mintty.github.io/ (compatibility)
- // Linux will hit this if you attempt `cat | docker login`, and Windows
- // will hit this if you attempt docker login from mintty where stdin
- // is a pipe, not a character based console.
- if flPassword == "" && !cli.isTerminalIn {
- return authconfig, fmt.Errorf("Error: Cannot perform an interactive logon from a non TTY device")
- }
- authconfig.Username = strings.TrimSpace(authconfig.Username)
- if flUser = strings.TrimSpace(flUser); flUser == "" {
- 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.")
- }
- cli.promptWithDefault("Username", authconfig.Username)
- flUser = readInput(cli.in, cli.out)
- flUser = strings.TrimSpace(flUser)
- if flUser == "" {
- flUser = authconfig.Username
- }
- }
- if flUser == "" {
- return authconfig, fmt.Errorf("Error: Non-null Username Required")
- }
- if flPassword == "" {
- oldState, err := term.SaveState(cli.inFd)
- if err != nil {
- return authconfig, err
- }
- fmt.Fprintf(cli.out, "Password: ")
- term.DisableEcho(cli.inFd, oldState)
- flPassword = readInput(cli.in, cli.out)
- fmt.Fprint(cli.out, "\n")
- term.RestoreTerminal(cli.inFd, oldState)
- if flPassword == "" {
- return authconfig, fmt.Errorf("Error: Password Required")
- }
- }
- authconfig.Username = flUser
- authconfig.Password = flPassword
- authconfig.ServerAddress = serverAddress
- authconfig.IdentityToken = ""
- return authconfig, nil
- }
- func readInput(in io.Reader, out io.Writer) string {
- reader := bufio.NewReader(in)
- line, _, err := reader.ReadLine()
- if err != nil {
- fmt.Fprintln(out, err.Error())
- os.Exit(1)
- }
- return string(line)
- }
- // getCredentials loads the user credentials from a credentials store.
- // The store is determined by the config file settings.
- func getCredentials(c *configfile.ConfigFile, serverAddress string) (types.AuthConfig, error) {
- s := loadCredentialsStore(c)
- return s.Get(serverAddress)
- }
- func getAllCredentials(c *configfile.ConfigFile) (map[string]types.AuthConfig, error) {
- s := loadCredentialsStore(c)
- return s.GetAll()
- }
- // storeCredentials saves the user credentials in a credentials store.
- // The store is determined by the config file settings.
- func storeCredentials(c *configfile.ConfigFile, auth types.AuthConfig) error {
- 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.
- func eraseCredentials(c *configfile.ConfigFile, serverAddress string) error {
- s := loadCredentialsStore(c)
- return s.Erase(serverAddress)
- }
- // loadCredentialsStore initializes a new credentials store based
- // in the settings provided in the configuration file.
- func loadCredentialsStore(c *configfile.ConfigFile) credentials.Store {
- if c.CredentialsStore != "" {
- return credentials.NewNativeStore(c)
- }
- return credentials.NewFileStore(c)
- }
|