github.com/ncdc/docker@v0.10.1-0.20160129113957-6c6729ef5b74/api/client/login.go (about) 1 package client 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "os" 8 "runtime" 9 "strings" 10 11 Cli "github.com/docker/docker/cli" 12 flag "github.com/docker/docker/pkg/mflag" 13 "github.com/docker/docker/pkg/term" 14 "github.com/docker/docker/registry" 15 "github.com/docker/engine-api/client" 16 "github.com/docker/engine-api/types" 17 ) 18 19 // CmdLogin logs in or registers a user to a Docker registry service. 20 // 21 // If no server is specified, the user will be logged into or registered to the registry's index server. 22 // 23 // Usage: docker login SERVER 24 func (cli *DockerCli) CmdLogin(args ...string) error { 25 cmd := Cli.Subcmd("login", []string{"[SERVER]"}, Cli.DockerCommands["login"].Description+".\nIf no server is specified \""+registry.IndexServer+"\" is the default.", true) 26 cmd.Require(flag.Max, 1) 27 28 flUser := cmd.String([]string{"u", "-username"}, "", "Username") 29 flPassword := cmd.String([]string{"p", "-password"}, "", "Password") 30 flEmail := cmd.String([]string{"e", "-email"}, "", "Email") 31 32 cmd.ParseFlags(args, true) 33 34 // On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210 35 if runtime.GOOS == "windows" { 36 cli.in = os.Stdin 37 } 38 39 serverAddress := registry.IndexServer 40 if len(cmd.Args()) > 0 { 41 serverAddress = cmd.Arg(0) 42 } 43 44 authConfig, err := cli.configureAuth(*flUser, *flPassword, *flEmail, serverAddress) 45 if err != nil { 46 return err 47 } 48 49 response, err := cli.client.RegistryLogin(authConfig) 50 if err != nil { 51 if client.IsErrUnauthorized(err) { 52 delete(cli.configFile.AuthConfigs, serverAddress) 53 if err2 := cli.configFile.Save(); err2 != nil { 54 fmt.Fprintf(cli.out, "WARNING: could not save config file: %v\n", err2) 55 } 56 } 57 return err 58 } 59 60 if err := cli.configFile.Save(); err != nil { 61 return fmt.Errorf("Error saving config file: %v", err) 62 } 63 fmt.Fprintf(cli.out, "WARNING: login credentials saved in %s\n", cli.configFile.Filename()) 64 65 if response.Status != "" { 66 fmt.Fprintf(cli.out, "%s\n", response.Status) 67 } 68 return nil 69 } 70 71 func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) { 72 if configDefault == "" { 73 fmt.Fprintf(cli.out, "%s: ", prompt) 74 } else { 75 fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault) 76 } 77 } 78 79 func (cli *DockerCli) configureAuth(flUser, flPassword, flEmail, serverAddress string) (types.AuthConfig, error) { 80 authconfig, ok := cli.configFile.AuthConfigs[serverAddress] 81 if !ok { 82 authconfig = types.AuthConfig{} 83 } 84 85 if flUser == "" { 86 cli.promptWithDefault("Username", authconfig.Username) 87 flUser = readInput(cli.in, cli.out) 88 flUser = strings.TrimSpace(flUser) 89 if flUser == "" { 90 flUser = authconfig.Username 91 } 92 } 93 94 if flPassword == "" { 95 oldState, err := term.SaveState(cli.inFd) 96 if err != nil { 97 return authconfig, err 98 } 99 fmt.Fprintf(cli.out, "Password: ") 100 term.DisableEcho(cli.inFd, oldState) 101 102 flPassword = readInput(cli.in, cli.out) 103 fmt.Fprint(cli.out, "\n") 104 105 term.RestoreTerminal(cli.inFd, oldState) 106 if flPassword == "" { 107 return authconfig, fmt.Errorf("Error : Password Required") 108 } 109 } 110 111 // Assume that a different username means they may not want to use 112 // the email from the config file, so prompt it 113 if flUser != authconfig.Username { 114 if flEmail == "" { 115 cli.promptWithDefault("Email", authconfig.Email) 116 flEmail = readInput(cli.in, cli.out) 117 if flEmail == "" { 118 flEmail = authconfig.Email 119 } 120 } 121 } else { 122 // However, if they don't override the username use the 123 // email from the cmd line if specified. IOW, allow 124 // then to change/override them. And if not specified, just 125 // use what's in the config file 126 if flEmail == "" { 127 flEmail = authconfig.Email 128 } 129 } 130 authconfig.Username = flUser 131 authconfig.Password = flPassword 132 authconfig.Email = flEmail 133 authconfig.ServerAddress = serverAddress 134 cli.configFile.AuthConfigs[serverAddress] = authconfig 135 return authconfig, nil 136 } 137 138 func readInput(in io.Reader, out io.Writer) string { 139 reader := bufio.NewReader(in) 140 line, _, err := reader.ReadLine() 141 if err != nil { 142 fmt.Fprintln(out, err.Error()) 143 os.Exit(1) 144 } 145 return string(line) 146 }