From bbf9135adcaec9edc2e9d0ebce6a78ba3ade3689 Mon Sep 17 00:00:00 2001 From: shin- Date: Tue, 22 Oct 2013 20:48:29 +0200 Subject: [PATCH 1/7] Added HTTPAuthDecorator --- utils/http.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/utils/http.go b/utils/http.go index 5eb77d1949..463d3b4fdd 100644 --- a/utils/http.go +++ b/utils/http.go @@ -107,6 +107,23 @@ func (h *HTTPMetaHeadersDecorator) ChangeRequest(req *http.Request) (newReq *htt return req, nil } +type HTTPAuthDecorator struct { + login string + password string +} + +func NewHTTPAuthDecorator(login, password string) HTTPRequestDecorator { + ret := new(HTTPAuthDecorator) + ret.login = login + ret.password = password + return ret +} + +func (self *HTTPAuthDecorator) ChangeRequest(req *http.Request) (*http.Request, error) { + req.SetBasicAuth(self.login, self.password) + return req, nil +} + // HTTPRequestFactory creates an HTTP request // and applies a list of decorators on the request. type HTTPRequestFactory struct { @@ -119,6 +136,10 @@ func NewHTTPRequestFactory(d ...HTTPRequestDecorator) *HTTPRequestFactory { } } +func (self *HTTPRequestFactory) AddDecorator(d... HTTPRequestDecorator) { + self.decorators = append(self.decorators, d...) +} + // NewRequest() creates a new *http.Request, // applies all decorators in the HTTPRequestFactory on the request, // then applies decorators provided by d on the request. @@ -144,5 +165,6 @@ func (h *HTTPRequestFactory) NewRequest(method, urlStr string, body io.Reader, d return nil, err } } + Debugf("%v -- HEADERS: %v", req.URL, req.Header) return req, err } From 045989e3d824f577cd90a6386b66a5814e703766 Mon Sep 17 00:00:00 2001 From: shin- Date: Tue, 22 Oct 2013 20:49:13 +0200 Subject: [PATCH 2/7] Use basic auth for private registries when over HTTPS. RequestFactory is no longer a singleton (can be different for different instances of Registry) Registry now has an indexEndpoint member Registry methods that needed the indexEndpoint parameter no longer do so Registry methods will only use token auth where applicable if basic auth is not enabled. --- registry/registry.go | 62 +++++++++++++++++++++++++++++---------- registry/registry_test.go | 9 +++--- server.go | 43 ++++++++++++--------------- 3 files changed, 70 insertions(+), 44 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 6aea458e99..c39ecfe5ac 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -160,7 +160,9 @@ func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]s if err != nil { return nil, err } - req.Header.Set("Authorization", "Token "+strings.Join(token, ", ")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } res, err := doWithCookies(r.client, req) if err != nil { return nil, err @@ -193,7 +195,9 @@ func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) boo if err != nil { return false } - req.Header.Set("Authorization", "Token "+strings.Join(token, ", ")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } res, err := doWithCookies(r.client, req) if err != nil { return false @@ -209,7 +213,9 @@ func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([ if err != nil { return nil, -1, fmt.Errorf("Failed to download json: %s", err) } - req.Header.Set("Authorization", "Token "+strings.Join(token, ", ")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } res, err := doWithCookies(r.client, req) if err != nil { return nil, -1, fmt.Errorf("Failed to download json: %s", err) @@ -236,7 +242,9 @@ func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string) ( if err != nil { return nil, fmt.Errorf("Error while getting from the server: %s\n", err) } - req.Header.Set("Authorization", "Token "+strings.Join(token, ", ")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } res, err := doWithCookies(r.client, req) if err != nil { return nil, err @@ -262,7 +270,9 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [ if err != nil { return nil, err } - req.Header.Set("Authorization", "Token "+strings.Join(token, ", ")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } res, err := doWithCookies(r.client, req) if err != nil { return nil, err @@ -290,7 +300,8 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [ return nil, fmt.Errorf("Could not reach any registry endpoint") } -func (r *Registry) GetRepositoryData(indexEp, remote string) (*RepositoryData, error) { +func (r *Registry) GetRepositoryData(remote string) (*RepositoryData, error) { + indexEp := r.indexEndpoint repositoryTarget := fmt.Sprintf("%srepositories/%s/images", indexEp, remote) utils.Debugf("[registry] Calling GET %s", repositoryTarget) @@ -364,7 +375,9 @@ func (r *Registry) PushImageChecksumRegistry(imgData *ImgData, registry string, if err != nil { return err } - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } req.Header.Set("X-Docker-Checksum", imgData.Checksum) res, err := doWithCookies(r.client, req) @@ -401,7 +414,9 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis return err } req.Header.Add("Content-type", "application/json") - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } res, err := doWithCookies(r.client, req) if err != nil { @@ -436,7 +451,9 @@ func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registr } req.ContentLength = -1 req.TransferEncoding = []string{"chunked"} - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } res, err := doWithCookies(r.client, req) if err != nil { return "", fmt.Errorf("Failed to upload layer: %s", err) @@ -465,7 +482,9 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token return err } req.Header.Add("Content-type", "application/json") - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } req.ContentLength = int64(len(revision)) res, err := doWithCookies(r.client, req) if err != nil { @@ -478,8 +497,9 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token return nil } -func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) { +func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) { cleanImgList := []*ImgData{} + indexEp := r.indexEndpoint if validate { for _, elem := range imgList { @@ -583,6 +603,7 @@ func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData } func (r *Registry) SearchRepositories(term string) (*SearchResults, error) { + utils.Debugf("Index server: %s", r.indexEndpoint) u := auth.IndexServerAddress() + "search?q=" + url.QueryEscape(term) req, err := r.reqFactory.NewRequest("GET", u, nil) if err != nil { @@ -644,12 +665,13 @@ type ImgData struct { } type Registry struct { - client *http.Client - authConfig *auth.AuthConfig - reqFactory *utils.HTTPRequestFactory + client *http.Client + authConfig *auth.AuthConfig + reqFactory *utils.HTTPRequestFactory + indexEndpoint string } -func NewRegistry(root string, authConfig *auth.AuthConfig, factory *utils.HTTPRequestFactory) (r *Registry, err error) { +func NewRegistry(authConfig *auth.AuthConfig, factory *utils.HTTPRequestFactory, indexEndpoint string) (r *Registry, err error) { httpTransport := &http.Transport{ DisableKeepAlives: true, Proxy: http.ProxyFromEnvironment, @@ -660,12 +682,22 @@ func NewRegistry(root string, authConfig *auth.AuthConfig, factory *utils.HTTPRe client: &http.Client{ Transport: httpTransport, }, + indexEndpoint: indexEndpoint, } r.client.Jar, err = cookiejar.New(nil) if err != nil { return nil, err } + // If we're working with a private registry over HTTPS, send Basic Auth headers + // alongside our requests. + if indexEndpoint != auth.IndexServerAddress() && strings.HasPrefix(indexEndpoint, "https://") { + utils.Debugf("Endpoint %s is eligible for private registry auth. Enabling decorator.", indexEndpoint) + dec := utils.NewHTTPAuthDecorator(authConfig.Username, authConfig.Password) + factory.AddDecorator(dec) + } + r.reqFactory = factory return r, nil } + diff --git a/registry/registry_test.go b/registry/registry_test.go index fb43da66aa..69eb25b247 100644 --- a/registry/registry_test.go +++ b/registry/registry_test.go @@ -15,7 +15,7 @@ var ( func spawnTestRegistry(t *testing.T) *Registry { authConfig := &auth.AuthConfig{} - r, err := NewRegistry("", authConfig, utils.NewHTTPRequestFactory()) + r, err := NewRegistry(authConfig, utils.NewHTTPRequestFactory(), makeURL("/v1/")) if err != nil { t.Fatal(err) } @@ -99,7 +99,7 @@ func TestGetRemoteTags(t *testing.T) { func TestGetRepositoryData(t *testing.T) { r := spawnTestRegistry(t) - data, err := r.GetRepositoryData(makeURL("/v1/"), "foo42/bar") + data, err := r.GetRepositoryData("foo42/bar") if err != nil { t.Fatal(err) } @@ -168,15 +168,14 @@ func TestPushImageJSONIndex(t *testing.T) { Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2", }, } - ep := makeURL("/v1/") - repoData, err := r.PushImageJSONIndex(ep, "foo42/bar", imgData, false, nil) + repoData, err := r.PushImageJSONIndex("foo42/bar", imgData, false, nil) if err != nil { t.Fatal(err) } if repoData == nil { t.Fatal("Expected RepositoryData object") } - repoData, err = r.PushImageJSONIndex(ep, "foo42/bar", imgData, true, []string{ep}) + repoData, err = r.PushImageJSONIndex("foo42/bar", imgData, true, []string{r.indexEndpoint}) if err != nil { t.Fatal(err) } diff --git a/server.go b/server.go index a5ab4f2646..40ee7e3c42 100644 --- a/server.go +++ b/server.go @@ -425,7 +425,7 @@ func (srv *Server) recursiveLoad(address, tmpImageDir string) error { } func (srv *Server) ImagesSearch(term string) ([]registry.SearchResult, error) { - r, err := registry.NewRegistry(srv.runtime.config.Root, nil, srv.HTTPRequestFactory(nil)) + r, err := registry.NewRegistry(nil, srv.HTTPRequestFactory(nil), auth.IndexServerAddress()) if err != nil { return nil, err } @@ -816,10 +816,10 @@ func (srv *Server) pullImage(r *registry.Registry, out io.Writer, imgID, endpoin return nil } -func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, localName, remoteName, askedTag, indexEp string, sf *utils.StreamFormatter, parallel bool) error { +func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, localName, remoteName, askedTag string, sf *utils.StreamFormatter, parallel bool) error { out.Write(sf.FormatStatus("", "Pulling repository %s", localName)) - repoData, err := r.GetRepositoryData(indexEp, remoteName) + repoData, err := r.GetRepositoryData(remoteName) if err != nil { return err } @@ -989,11 +989,6 @@ func (srv *Server) poolRemove(kind, key string) error { } func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *utils.StreamFormatter, authConfig *auth.AuthConfig, metaHeaders map[string][]string, parallel bool) error { - r, err := registry.NewRegistry(srv.runtime.config.Root, authConfig, srv.HTTPRequestFactory(metaHeaders)) - if err != nil { - return err - } - out = utils.NewWriteFlusher(out) c, err := srv.poolAdd("pull", localName+":"+tag) @@ -1014,12 +1009,17 @@ func (srv *Server) ImagePull(localName string, tag string, out io.Writer, sf *ut return err } + r, err := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), endpoint) + if err != nil { + return err + } + if endpoint == auth.IndexServerAddress() { // If pull "index.docker.io/foo/bar", it's stored locally under "foo/bar" localName = remoteName } - if err = srv.pullRepository(r, out, localName, remoteName, tag, endpoint, sf, parallel); err != nil { + if err = srv.pullRepository(r, out, localName, remoteName, tag, sf, parallel); err != nil { return err } @@ -1081,7 +1081,7 @@ func flatten(slc [][]*registry.ImgData) []*registry.ImgData { return result } -func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, indexEp string, sf *utils.StreamFormatter) error { +func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName, remoteName string, localRepo map[string]string, sf *utils.StreamFormatter) error { out = utils.NewWriteFlusher(out) imgList, err := srv.getImageList(localRepo) if err != nil { @@ -1091,7 +1091,7 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName out.Write(sf.FormatStatus("", "Sending image list")) var repoData *registry.RepositoryData - repoData, err = r.PushImageJSONIndex(indexEp, remoteName, flattenedImgList, false, nil) + repoData, err = r.PushImageJSONIndex(remoteName, flattenedImgList, false, nil) if err != nil { return err } @@ -1137,7 +1137,7 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName } } - if _, err := r.PushImageJSONIndex(indexEp, remoteName, flattenedImgList, true, repoData.Endpoints); err != nil { + if _, err := r.PushImageJSONIndex(remoteName, flattenedImgList, true, repoData.Endpoints); err != nil { return err } @@ -1203,7 +1203,7 @@ func (srv *Server) ImagePush(localName string, out io.Writer, sf *utils.StreamFo out = utils.NewWriteFlusher(out) img, err := srv.runtime.graph.Get(localName) - r, err2 := registry.NewRegistry(srv.runtime.config.Root, authConfig, srv.HTTPRequestFactory(metaHeaders)) + r, err2 := registry.NewRegistry(authConfig, srv.HTTPRequestFactory(metaHeaders), endpoint) if err2 != nil { return err2 } @@ -1213,7 +1213,7 @@ func (srv *Server) ImagePush(localName string, out io.Writer, sf *utils.StreamFo out.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", localName, reposLen)) // If it fails, try to get the repository if localRepo, exists := srv.runtime.repositories.Repositories[localName]; exists { - if err := srv.pushRepository(r, out, localName, remoteName, localRepo, endpoint, sf); err != nil { + if err := srv.pushRepository(r, out, localName, remoteName, localRepo, sf); err != nil { return err } return nil @@ -1852,7 +1852,6 @@ func NewServer(eng *engine.Engine, config *DaemonConfig) (*Server, error) { pushingPool: make(map[string]chan struct{}), events: make([]utils.JSONMessage, 0, 64), //only keeps the 64 last events listeners: make(map[string]chan utils.JSONMessage), - reqFactory: nil, } runtime.srv = srv return srv, nil @@ -1861,15 +1860,12 @@ func NewServer(eng *engine.Engine, config *DaemonConfig) (*Server, error) { func (srv *Server) HTTPRequestFactory(metaHeaders map[string][]string) *utils.HTTPRequestFactory { srv.Lock() defer srv.Unlock() - if srv.reqFactory == nil { - ud := utils.NewHTTPUserAgentDecorator(srv.versionInfos()...) - md := &utils.HTTPMetaHeadersDecorator{ - Headers: metaHeaders, - } - factory := utils.NewHTTPRequestFactory(ud, md) - srv.reqFactory = factory + ud := utils.NewHTTPUserAgentDecorator(srv.versionInfos()...) + md := &utils.HTTPMetaHeadersDecorator{ + Headers: metaHeaders, } - return srv.reqFactory + factory := utils.NewHTTPRequestFactory(ud, md) + return factory } func (srv *Server) LogEvent(action, id, from string) *utils.JSONMessage { @@ -1904,6 +1900,5 @@ type Server struct { pushingPool map[string]chan struct{} events []utils.JSONMessage listeners map[string]chan utils.JSONMessage - reqFactory *utils.HTTPRequestFactory Eng *engine.Engine } From a02bc8a5dbca763a2a245cf0ca17ff5a21d5b52b Mon Sep 17 00:00:00 2001 From: shin- Date: Tue, 22 Oct 2013 20:57:48 +0200 Subject: [PATCH 3/7] gofmt --- registry/registry.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index c39ecfe5ac..99f3403a4c 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -665,9 +665,9 @@ type ImgData struct { } type Registry struct { - client *http.Client - authConfig *auth.AuthConfig - reqFactory *utils.HTTPRequestFactory + client *http.Client + authConfig *auth.AuthConfig + reqFactory *utils.HTTPRequestFactory indexEndpoint string } @@ -700,4 +700,3 @@ func NewRegistry(authConfig *auth.AuthConfig, factory *utils.HTTPRequestFactory, r.reqFactory = factory return r, nil } - From ec4863ae5582d8e7a9dccb57d7f5f3e21c2481ef Mon Sep 17 00:00:00 2001 From: shin- Date: Wed, 23 Oct 2013 17:56:40 +0200 Subject: [PATCH 4/7] Factorized auth token setting --- registry/registry.go | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 99f3403a4c..ef561fea06 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -153,6 +153,13 @@ func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) { return res, err } +func setTokenAuth(req *http.Request, token []string) (*http.Request) { + if req.Header.Get("Authorization") == "" { // Don't override + req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) + } + return req +} + // Retrieve the history of a given image from the Registry. // Return a list of the parent's json (requested image included) func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]string, error) { @@ -160,9 +167,7 @@ func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]s if err != nil { return nil, err } - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return nil, err @@ -195,9 +200,7 @@ func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) boo if err != nil { return false } - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return false @@ -213,9 +216,7 @@ func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([ if err != nil { return nil, -1, fmt.Errorf("Failed to download json: %s", err) } - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return nil, -1, fmt.Errorf("Failed to download json: %s", err) @@ -242,9 +243,7 @@ func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string) ( if err != nil { return nil, fmt.Errorf("Error while getting from the server: %s\n", err) } - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return nil, err @@ -375,9 +374,7 @@ func (r *Registry) PushImageChecksumRegistry(imgData *ImgData, registry string, if err != nil { return err } - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) req.Header.Set("X-Docker-Checksum", imgData.Checksum) res, err := doWithCookies(r.client, req) @@ -414,9 +411,7 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis return err } req.Header.Add("Content-type", "application/json") - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { @@ -451,9 +446,7 @@ func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registr } req.ContentLength = -1 req.TransferEncoding = []string{"chunked"} - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return "", fmt.Errorf("Failed to upload layer: %s", err) @@ -482,9 +475,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token return err } req.Header.Add("Content-type", "application/json") - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) req.ContentLength = int64(len(revision)) res, err := doWithCookies(r.client, req) if err != nil { From 3b5010e90bd51ba3630f48091ed70111d26dd31a Mon Sep 17 00:00:00 2001 From: shin- Date: Wed, 23 Oct 2013 18:00:40 +0200 Subject: [PATCH 5/7] missed one call to setTokenAuth --- registry/registry.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index ef561fea06..0a8d1ddaa3 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -153,7 +153,7 @@ func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) { return res, err } -func setTokenAuth(req *http.Request, token []string) (*http.Request) { +func setTokenAuth(req *http.Request, token []string) *http.Request { if req.Header.Get("Authorization") == "" { // Don't override req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) } @@ -269,9 +269,7 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [ if err != nil { return nil, err } - if req.Header.Get("Authorization") == "" { // Don't override - req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) - } + req = setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return nil, err From 3f921639894d3eca72c9ae105d3ad4f386651caa Mon Sep 17 00:00:00 2001 From: shin- Date: Mon, 4 Nov 2013 21:49:34 +0100 Subject: [PATCH 6/7] Don't return req as result of setTokenAuth --- registry/registry.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 0a8d1ddaa3..6c9255aa46 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -153,11 +153,10 @@ func doWithCookies(c *http.Client, req *http.Request) (*http.Response, error) { return res, err } -func setTokenAuth(req *http.Request, token []string) *http.Request { +func setTokenAuth(req *http.Request, token []string) { if req.Header.Get("Authorization") == "" { // Don't override req.Header.Set("Authorization", "Token "+strings.Join(token, ",")) } - return req } // Retrieve the history of a given image from the Registry. @@ -167,7 +166,7 @@ func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]s if err != nil { return nil, err } - req = setTokenAuth(req, token) + setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return nil, err @@ -200,7 +199,7 @@ func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) boo if err != nil { return false } - req = setTokenAuth(req, token) + setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return false @@ -216,7 +215,7 @@ func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([ if err != nil { return nil, -1, fmt.Errorf("Failed to download json: %s", err) } - req = setTokenAuth(req, token) + setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return nil, -1, fmt.Errorf("Failed to download json: %s", err) @@ -243,7 +242,7 @@ func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string) ( if err != nil { return nil, fmt.Errorf("Error while getting from the server: %s\n", err) } - req = setTokenAuth(req, token) + setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return nil, err @@ -269,7 +268,7 @@ func (r *Registry) GetRemoteTags(registries []string, repository string, token [ if err != nil { return nil, err } - req = setTokenAuth(req, token) + setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return nil, err @@ -372,7 +371,7 @@ func (r *Registry) PushImageChecksumRegistry(imgData *ImgData, registry string, if err != nil { return err } - req = setTokenAuth(req, token) + setTokenAuth(req, token) req.Header.Set("X-Docker-Checksum", imgData.Checksum) res, err := doWithCookies(r.client, req) @@ -409,7 +408,7 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis return err } req.Header.Add("Content-type", "application/json") - req = setTokenAuth(req, token) + setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { @@ -444,7 +443,7 @@ func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registr } req.ContentLength = -1 req.TransferEncoding = []string{"chunked"} - req = setTokenAuth(req, token) + setTokenAuth(req, token) res, err := doWithCookies(r.client, req) if err != nil { return "", fmt.Errorf("Failed to upload layer: %s", err) @@ -473,7 +472,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token return err } req.Header.Add("Content-type", "application/json") - req = setTokenAuth(req, token) + setTokenAuth(req, token) req.ContentLength = int64(len(revision)) res, err := doWithCookies(r.client, req) if err != nil { From 9be5db8704be5bda02484c374f4bd9b197d5701b Mon Sep 17 00:00:00 2001 From: shin- Date: Thu, 7 Nov 2013 19:36:02 +0100 Subject: [PATCH 7/7] Handle 401 response in auth.Login() for authed private registries --- auth/auth.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/auth/auth.go b/auth/auth.go index 62d8e7f522..85844a5472 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -223,6 +223,28 @@ func Login(authConfig *AuthConfig, factory *utils.HTTPRequestFactory) (string, e } else { return "", fmt.Errorf("Registration: %s", reqBody) } + } else if reqStatusCode == 401 { + // This case would happen with private registries where /v1/users is + // protected, so people can use `docker login` as an auth check. + req, err := factory.NewRequest("GET", serverAddress+"users/", nil) + req.SetBasicAuth(authConfig.Username, authConfig.Password) + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + if resp.StatusCode == 200 { + status = "Login Succeeded" + } else if resp.StatusCode == 401 { + return "", fmt.Errorf("Wrong login/password, please try again") + } else { + return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body, + resp.StatusCode, resp.Header) + } } else { return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody) }