1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #4270 from DevTable/fixregistryauth

Fix registry auth and remove other hidden ping commands from client code
This commit is contained in:
Guillaume J. Charmes 2014-03-03 17:34:21 -08:00
commit 0eeb146398
6 changed files with 60 additions and 57 deletions

View file

@ -992,13 +992,13 @@ func (cli *DockerCli) CmdPush(args ...string) error {
cli.LoadConfigFile() cli.LoadConfigFile()
// Resolve the Repository name from fqn to endpoint + name // Resolve the Repository name from fqn to hostname + name
endpoint, _, err := registry.ResolveRepositoryName(name) hostname, _, err := registry.ResolveRepositoryName(name)
if err != nil { if err != nil {
return err return err
} }
// Resolve the Auth config relevant for this server // Resolve the Auth config relevant for this server
authConfig := cli.configFile.ResolveAuthConfig(endpoint) authConfig := cli.configFile.ResolveAuthConfig(hostname)
// If we're not using a custom registry, we know the restrictions // If we're not using a custom registry, we know the restrictions
// applied to repository names and can warn the user in advance. // applied to repository names and can warn the user in advance.
// Custom repositories can have different rules, and we must also // Custom repositories can have different rules, and we must also
@ -1029,10 +1029,10 @@ func (cli *DockerCli) CmdPush(args ...string) error {
if err := push(authConfig); err != nil { if err := push(authConfig); err != nil {
if strings.Contains(err.Error(), "Status 401") { if strings.Contains(err.Error(), "Status 401") {
fmt.Fprintln(cli.out, "\nPlease login prior to push:") fmt.Fprintln(cli.out, "\nPlease login prior to push:")
if err := cli.CmdLogin(endpoint); err != nil { if err := cli.CmdLogin(hostname); err != nil {
return err return err
} }
authConfig := cli.configFile.ResolveAuthConfig(endpoint) authConfig := cli.configFile.ResolveAuthConfig(hostname)
return push(authConfig) return push(authConfig)
} }
return err return err
@ -1057,8 +1057,8 @@ func (cli *DockerCli) CmdPull(args ...string) error {
*tag = parsedTag *tag = parsedTag
} }
// Resolve the Repository name from fqn to endpoint + name // Resolve the Repository name from fqn to hostname + name
endpoint, _, err := registry.ResolveRepositoryName(remote) hostname, _, err := registry.ResolveRepositoryName(remote)
if err != nil { if err != nil {
return err return err
} }
@ -1066,7 +1066,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
cli.LoadConfigFile() cli.LoadConfigFile()
// Resolve the Auth config relevant for this server // Resolve the Auth config relevant for this server
authConfig := cli.configFile.ResolveAuthConfig(endpoint) authConfig := cli.configFile.ResolveAuthConfig(hostname)
v := url.Values{} v := url.Values{}
v.Set("fromImage", remote) v.Set("fromImage", remote)
v.Set("tag", *tag) v.Set("tag", *tag)
@ -1088,10 +1088,10 @@ func (cli *DockerCli) CmdPull(args ...string) error {
if err := pull(authConfig); err != nil { if err := pull(authConfig); err != nil {
if strings.Contains(err.Error(), "Status 401") { if strings.Contains(err.Error(), "Status 401") {
fmt.Fprintln(cli.out, "\nPlease login prior to pull:") fmt.Fprintln(cli.out, "\nPlease login prior to pull:")
if err := cli.CmdLogin(endpoint); err != nil { if err := cli.CmdLogin(hostname); err != nil {
return err return err
} }
authConfig := cli.configFile.ResolveAuthConfig(endpoint) authConfig := cli.configFile.ResolveAuthConfig(hostname)
return pull(authConfig) return pull(authConfig)
} }
return err return err
@ -1768,8 +1768,8 @@ func (cli *DockerCli) CmdRun(args ...string) error {
v.Set("fromImage", repos) v.Set("fromImage", repos)
v.Set("tag", tag) v.Set("tag", tag)
// Resolve the Repository name from fqn to endpoint + name // Resolve the Repository name from fqn to hostname + name
endpoint, _, err := registry.ResolveRepositoryName(repos) hostname, _, err := registry.ResolveRepositoryName(repos)
if err != nil { if err != nil {
return err return err
} }
@ -1778,7 +1778,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
cli.LoadConfigFile() cli.LoadConfigFile()
// Resolve the Auth config relevant for this server // Resolve the Auth config relevant for this server
authConfig := cli.configFile.ResolveAuthConfig(endpoint) authConfig := cli.configFile.ResolveAuthConfig(hostname)
buf, err := json.Marshal(authConfig) buf, err := json.Marshal(authConfig)
if err != nil { if err != nil {
return err return err

View file

@ -252,50 +252,39 @@ func Login(authConfig *AuthConfig, factory *utils.HTTPRequestFactory) (string, e
} }
// this method matches a auth configuration to a server address or a url // this method matches a auth configuration to a server address or a url
func (config *ConfigFile) ResolveAuthConfig(registry string) AuthConfig { func (config *ConfigFile) ResolveAuthConfig(hostname string) AuthConfig {
if registry == IndexServerAddress() || len(registry) == 0 { if hostname == IndexServerAddress() || len(hostname) == 0 {
// default to the index server // default to the index server
return config.Configs[IndexServerAddress()] return config.Configs[IndexServerAddress()]
} }
// if it's not the index server there are three cases:
//
// 1. a full config url -> it should be used as is
// 2. a full url, but with the wrong protocol
// 3. a hostname, with an optional port
//
// as there is only one auth entry which is fully qualified we need to start
// parsing and matching
swapProtocol := func(url string) string { // First try the happy case
if strings.HasPrefix(url, "http:") { if c, found := config.Configs[hostname]; found {
return strings.Replace(url, "http:", "https:", 1) return c
}
if strings.HasPrefix(url, "https:") {
return strings.Replace(url, "https:", "http:", 1)
}
return url
} }
resolveIgnoringProtocol := func(url string) AuthConfig { convertToHostname := func(url string) string {
if c, found := config.Configs[url]; found { stripped := url
return c if strings.HasPrefix(url, "http://") {
stripped = strings.Replace(url, "http://", "", 1)
} else if strings.HasPrefix(url, "https://") {
stripped = strings.Replace(url, "https://", "", 1)
} }
registrySwappedProtocol := swapProtocol(url)
// now try to match with the different protocol nameParts := strings.SplitN(stripped, "/", 2)
if c, found := config.Configs[registrySwappedProtocol]; found {
return c return nameParts[0]
}
return AuthConfig{}
} }
// match both protocols as it could also be a server name like httpfoo // Maybe they have a legacy config file, we will iterate the keys converting
if strings.HasPrefix(registry, "http:") || strings.HasPrefix(registry, "https:") { // them to the new format and testing
return resolveIgnoringProtocol(registry) normalizedHostename := convertToHostname(hostname)
for registry, config := range config.Configs {
if registryHostname := convertToHostname(registry); registryHostname == normalizedHostename {
return config
}
} }
url := "https://" + registry // When all else fails, return an empty auth config
if !strings.Contains(registry, "/") { return AuthConfig{}
url = url + "/v1/"
}
return resolveIgnoringProtocol(url)
} }

View file

@ -108,6 +108,7 @@ func TestResolveAuthConfigFullURL(t *testing.T) {
} }
configFile.Configs["https://registry.example.com/v1/"] = registryAuth configFile.Configs["https://registry.example.com/v1/"] = registryAuth
configFile.Configs["http://localhost:8000/v1/"] = localAuth configFile.Configs["http://localhost:8000/v1/"] = localAuth
configFile.Configs["registry.com"] = registryAuth
validRegistries := map[string][]string{ validRegistries := map[string][]string{
"https://registry.example.com/v1/": { "https://registry.example.com/v1/": {
@ -122,6 +123,12 @@ func TestResolveAuthConfigFullURL(t *testing.T) {
"localhost:8000", "localhost:8000",
"localhost:8000/v1/", "localhost:8000/v1/",
}, },
"registry.com": {
"https://registry.com/v1/",
"http://registry.com/v1/",
"registry.com",
"registry.com/v1/",
},
} }
for configKey, registries := range validRegistries { for configKey, registries := range validRegistries {

View file

@ -92,7 +92,7 @@ func validateRepositoryName(repositoryName string) error {
return nil return nil
} }
// Resolves a repository name to a endpoint + name // Resolves a repository name to a hostname + name
func ResolveRepositoryName(reposName string) (string, string, error) { func ResolveRepositoryName(reposName string) (string, string, error) {
if strings.Contains(reposName, "://") { if strings.Contains(reposName, "://") {
// It cannot contain a scheme! // It cannot contain a scheme!
@ -118,11 +118,8 @@ func ResolveRepositoryName(reposName string) (string, string, error) {
if err := validateRepositoryName(reposName); err != nil { if err := validateRepositoryName(reposName); err != nil {
return "", "", err return "", "", err
} }
endpoint, err := ExpandAndVerifyRegistryUrl(hostname)
if err != nil { return hostname, reposName, nil
return "", "", err
}
return endpoint, reposName, err
} }
// this method expands the registry name as used in the prefix of a repo // this method expands the registry name as used in the prefix of a repo

View file

@ -145,7 +145,7 @@ func TestResolveRepositoryName(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
assertEqual(t, ep, "http://"+u+"/v1/", "Expected endpoint to be "+u) assertEqual(t, ep, u, "Expected endpoint to be "+u)
assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase") assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase")
} }

View file

@ -1331,7 +1331,12 @@ func (srv *Server) ImagePull(job *engine.Job) engine.Status {
defer srv.poolRemove("pull", localName+":"+tag) defer srv.poolRemove("pull", localName+":"+tag)
// Resolve the Repository name from fqn to endpoint + name // Resolve the Repository name from fqn to endpoint + name
endpoint, remoteName, err := registry.ResolveRepositoryName(localName) hostname, remoteName, err := registry.ResolveRepositoryName(localName)
if err != nil {
return job.Error(err)
}
endpoint, err := registry.ExpandAndVerifyRegistryUrl(hostname)
if err != nil { if err != nil {
return job.Error(err) return job.Error(err)
} }
@ -1534,7 +1539,12 @@ func (srv *Server) ImagePush(job *engine.Job) engine.Status {
defer srv.poolRemove("push", localName) defer srv.poolRemove("push", localName)
// Resolve the Repository name from fqn to endpoint + name // Resolve the Repository name from fqn to endpoint + name
endpoint, remoteName, err := registry.ResolveRepositoryName(localName) hostname, remoteName, err := registry.ResolveRepositoryName(localName)
if err != nil {
return job.Error(err)
}
endpoint, err := registry.ExpandAndVerifyRegistryUrl(hostname)
if err != nil { if err != nil {
return job.Error(err) return job.Error(err)
} }