diff --git a/api/client/create.go b/api/client/create.go index 17f0b67c06..7bddf26cd2 100644 --- a/api/client/create.go +++ b/api/client/create.go @@ -40,7 +40,7 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error { return err } - authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) + authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) encodedAuth, err := encodeAuthToBase64(authConfig) if err != nil { return err diff --git a/api/client/login.go b/api/client/login.go index 7ea23d7809..f224ff98b1 100644 --- a/api/client/login.go +++ b/api/client/login.go @@ -11,7 +11,6 @@ import ( Cli "github.com/docker/docker/cli" flag "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/term" - "github.com/docker/docker/registry" "github.com/docker/engine-api/client" "github.com/docker/engine-api/types" ) @@ -36,16 +35,7 @@ func (cli *DockerCli) CmdLogin(args ...string) error { cli.in = os.Stdin } - // The daemon `/info` endpoint informs us of the default registry being - // used. This is essential in cross-platforms environment, where for - // example a Linux client might be interacting with a Windows daemon, hence - // the default registry URL might be Windows specific. - serverAddress := registry.IndexServer - if info, err := cli.client.Info(); err != nil { - fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress) - } else { - serverAddress = info.IndexServerAddress - } + serverAddress := cli.electAuthServer() if len(cmd.Args()) > 0 { serverAddress = cmd.Arg(0) } diff --git a/api/client/logout.go b/api/client/logout.go index 3753cbbe74..556f40faff 100644 --- a/api/client/logout.go +++ b/api/client/logout.go @@ -5,7 +5,6 @@ import ( Cli "github.com/docker/docker/cli" flag "github.com/docker/docker/pkg/mflag" - "github.com/docker/docker/registry" ) // CmdLogout logs a user out from a Docker registry. @@ -14,12 +13,12 @@ import ( // // Usage: docker logout [SERVER] func (cli *DockerCli) CmdLogout(args ...string) error { - cmd := Cli.Subcmd("logout", []string{"[SERVER]"}, Cli.DockerCommands["logout"].Description+".\nIf no server is specified \""+registry.IndexServer+"\" is the default.", true) + cmd := Cli.Subcmd("logout", []string{"[SERVER]"}, Cli.DockerCommands["logout"].Description+".\nIf no server is specified, the default is defined by the daemon.", true) cmd.Require(flag.Max, 1) cmd.ParseFlags(args, true) - serverAddress := registry.IndexServer + serverAddress := cli.electAuthServer() if len(cmd.Args()) > 0 { serverAddress = cmd.Arg(0) } diff --git a/api/client/pull.go b/api/client/pull.go index 19220b96c0..61ff02cd81 100644 --- a/api/client/pull.go +++ b/api/client/pull.go @@ -54,7 +54,7 @@ func (cli *DockerCli) CmdPull(args ...string) error { return err } - authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) + authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "pull") if isTrusted() && !ref.HasDigest() { diff --git a/api/client/push.go b/api/client/push.go index 9e4972c308..01e7d9397f 100644 --- a/api/client/push.go +++ b/api/client/push.go @@ -42,7 +42,7 @@ func (cli *DockerCli) CmdPush(args ...string) error { return err } // Resolve the Auth config relevant for this server - authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) + authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "push") if isTrusted() { diff --git a/api/client/search.go b/api/client/search.go index 64bbb67ea7..2e1fcdafd3 100644 --- a/api/client/search.go +++ b/api/client/search.go @@ -36,7 +36,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error { return err } - authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, indexInfo) + authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, indexInfo) requestPrivilege := cli.registryAuthenticationPrivilegedFunc(indexInfo, "search") encodedAuth, err := encodeAuthToBase64(authConfig) diff --git a/api/client/trust.go b/api/client/trust.go index 220c3dbe32..753bcd6fc7 100644 --- a/api/client/trust.go +++ b/api/client/trust.go @@ -235,7 +235,7 @@ func (cli *DockerCli) trustedReference(ref reference.NamedTagged) (reference.Can } // Resolve the Auth config relevant for this server - authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) + authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) notaryRepo, err := cli.getNotaryRepository(repoInfo, authConfig) if err != nil { diff --git a/api/client/utils.go b/api/client/utils.go index 7d1cc73500..e87e593fe2 100644 --- a/api/client/utils.go +++ b/api/client/utils.go @@ -10,6 +10,7 @@ import ( gosignal "os/signal" "path/filepath" "runtime" + "strings" "time" "github.com/Sirupsen/logrus" @@ -21,6 +22,20 @@ import ( registrytypes "github.com/docker/engine-api/types/registry" ) +func (cli *DockerCli) electAuthServer() string { + // The daemon `/info` endpoint informs us of the default registry being + // used. This is essential in cross-platforms environment, where for + // example a Linux client might be interacting with a Windows daemon, hence + // the default registry URL might be Windows specific. + serverAddress := registry.IndexServer + if info, err := cli.client.Info(); err != nil { + fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress) + } else { + serverAddress = info.IndexServerAddress + } + return serverAddress +} + // encodeAuthToBase64 serializes the auth configuration as JSON base64 payload func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) { buf, err := json.Marshal(authConfig) @@ -162,3 +177,42 @@ func copyToFile(outfile string, r io.Reader) error { return nil } + +// resolveAuthConfig is like registry.ResolveAuthConfig, but if using the +// default index, it uses the default index name for the daemon's platform, +// not the client's platform. +func (cli *DockerCli) resolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registrytypes.IndexInfo) types.AuthConfig { + configKey := index.Name + if index.Official { + configKey = cli.electAuthServer() + } + + // First try the happy case + if c, found := authConfigs[configKey]; found || index.Official { + return c + } + + convertToHostname := func(url string) string { + stripped := url + if strings.HasPrefix(url, "http://") { + stripped = strings.Replace(url, "http://", "", 1) + } else if strings.HasPrefix(url, "https://") { + stripped = strings.Replace(url, "https://", "", 1) + } + + nameParts := strings.SplitN(stripped, "/", 2) + + return nameParts[0] + } + + // Maybe they have a legacy config file, we will iterate the keys converting + // them to the new format and testing + for registry, ac := range authConfigs { + if configKey == convertToHostname(registry) { + return ac + } + } + + // When all else fails, return an empty auth config + return types.AuthConfig{} +}