github.com/kobeld/docker@v1.12.0-rc1/api/client/registry.go (about) 1 package client 2 3 import ( 4 "bufio" 5 "encoding/base64" 6 "encoding/json" 7 "fmt" 8 "io" 9 "os" 10 "runtime" 11 "strings" 12 13 "golang.org/x/net/context" 14 15 "github.com/docker/docker/pkg/term" 16 "github.com/docker/docker/registry" 17 "github.com/docker/engine-api/types" 18 registrytypes "github.com/docker/engine-api/types/registry" 19 ) 20 21 // ElectAuthServer returns the default registry to use (by asking the daemon) 22 func (cli *DockerCli) ElectAuthServer(ctx context.Context) string { 23 // The daemon `/info` endpoint informs us of the default registry being 24 // used. This is essential in cross-platforms environment, where for 25 // example a Linux client might be interacting with a Windows daemon, hence 26 // the default registry URL might be Windows specific. 27 serverAddress := registry.IndexServer 28 if info, err := cli.client.Info(ctx); err != nil { 29 fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress) 30 } else { 31 serverAddress = info.IndexServerAddress 32 } 33 return serverAddress 34 } 35 36 // EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload 37 func EncodeAuthToBase64(authConfig types.AuthConfig) (string, error) { 38 buf, err := json.Marshal(authConfig) 39 if err != nil { 40 return "", err 41 } 42 return base64.URLEncoding.EncodeToString(buf), nil 43 } 44 45 // RegistryAuthenticationPrivilegedFunc return a RequestPrivilegeFunc from the specified registry index info 46 // for the given command. 47 func (cli *DockerCli) RegistryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) types.RequestPrivilegeFunc { 48 return func() (string, error) { 49 fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName) 50 indexServer := registry.GetAuthConfigKey(index) 51 authConfig, err := cli.ConfigureAuth("", "", indexServer, false) 52 if err != nil { 53 return "", err 54 } 55 return EncodeAuthToBase64(authConfig) 56 } 57 } 58 59 func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) { 60 if configDefault == "" { 61 fmt.Fprintf(cli.out, "%s: ", prompt) 62 } else { 63 fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault) 64 } 65 } 66 67 // ResolveAuthConfig is like registry.ResolveAuthConfig, but if using the 68 // default index, it uses the default index name for the daemon's platform, 69 // not the client's platform. 70 func (cli *DockerCli) ResolveAuthConfig(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig { 71 configKey := index.Name 72 if index.Official { 73 configKey = cli.ElectAuthServer(ctx) 74 } 75 76 a, _ := GetCredentials(cli.configFile, configKey) 77 return a 78 } 79 80 // RetrieveAuthConfigs return all credentials. 81 func (cli *DockerCli) RetrieveAuthConfigs() map[string]types.AuthConfig { 82 acs, _ := GetAllCredentials(cli.configFile) 83 return acs 84 } 85 86 // ConfigureAuth returns an AuthConfig from the specified user, password and server. 87 func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) { 88 // On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210 89 if runtime.GOOS == "windows" { 90 cli.in = os.Stdin 91 } 92 93 authconfig, err := GetCredentials(cli.configFile, serverAddress) 94 if err != nil { 95 return authconfig, err 96 } 97 98 // Some links documenting this: 99 // - https://code.google.com/archive/p/mintty/issues/56 100 // - https://github.com/docker/docker/issues/15272 101 // - https://mintty.github.io/ (compatibility) 102 // Linux will hit this if you attempt `cat | docker login`, and Windows 103 // will hit this if you attempt docker login from mintty where stdin 104 // is a pipe, not a character based console. 105 if flPassword == "" && !cli.isTerminalIn { 106 return authconfig, fmt.Errorf("Error: Cannot perform an interactive logon from a non TTY device") 107 } 108 109 authconfig.Username = strings.TrimSpace(authconfig.Username) 110 111 if flUser = strings.TrimSpace(flUser); flUser == "" { 112 if isDefaultRegistry { 113 // if this is a defauly registry (docker hub), then display the following message. 114 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.") 115 } 116 cli.promptWithDefault("Username", authconfig.Username) 117 flUser = readInput(cli.in, cli.out) 118 flUser = strings.TrimSpace(flUser) 119 if flUser == "" { 120 flUser = authconfig.Username 121 } 122 } 123 if flUser == "" { 124 return authconfig, fmt.Errorf("Error: Non-null Username Required") 125 } 126 if flPassword == "" { 127 oldState, err := term.SaveState(cli.inFd) 128 if err != nil { 129 return authconfig, err 130 } 131 fmt.Fprintf(cli.out, "Password: ") 132 term.DisableEcho(cli.inFd, oldState) 133 134 flPassword = readInput(cli.in, cli.out) 135 fmt.Fprint(cli.out, "\n") 136 137 term.RestoreTerminal(cli.inFd, oldState) 138 if flPassword == "" { 139 return authconfig, fmt.Errorf("Error: Password Required") 140 } 141 } 142 143 authconfig.Username = flUser 144 authconfig.Password = flPassword 145 authconfig.ServerAddress = serverAddress 146 authconfig.IdentityToken = "" 147 148 return authconfig, nil 149 } 150 151 func readInput(in io.Reader, out io.Writer) string { 152 reader := bufio.NewReader(in) 153 line, _, err := reader.ReadLine() 154 if err != nil { 155 fmt.Fprintln(out, err.Error()) 156 os.Exit(1) 157 } 158 return string(line) 159 }