//Pull Image from Registry or Hub depending on image name func Login(registry string) (bool, error) { logrus.Info("log in: ", registry) if strings.Contains(registry, "docker") { registry = "https://" + registry + "/v2" } else { registry = "http://" + registry + "/v2" } client := httpclient.Get() request, err := http.NewRequest("GET", registry, nil) response, err := client.Do(request) if err != nil { return false, fmt.Errorf("log in %v: %v", registry, err) } authorized := response.StatusCode != http.StatusUnauthorized if !authorized { logrus.Info("Unauthorized access") err := AuthenticateResponse(response, request) if err != nil { if err == xerrors.Unauthorized { authorized = false } return false, err } else { authorized = true } } return authorized, nil }
// NewReverseProxy returns a new ReverseProxy that load-balances the proxy requests between multiple hosts defined by the RegistryMapping in the database // It also allows to define a chain of filter functions to process the outgoing response(s) func NewReverseProxy(filters []FilterFunc) *ReverseProxy { director := func(request *http.Request) { inr := context.Get(request, "in_req").(*http.Request) host, _ := database.GetRegistryMapping(mux.Vars(inr)["digest"]) out, _ := url.Parse(host) request.URL.Scheme = out.Scheme request.URL.Host = out.Host client := httpclient.Get() req, _ := http.NewRequest("HEAD", request.URL.String(), nil) resp, err := client.Do(req) if err != nil { logrus.Errorf("response error: %v", err) return } if resp.StatusCode == http.StatusUnauthorized { logrus.Info("pull from clair is unauthorized") docker.AuthenticateResponse(resp, request) } r, _ := http.NewRequest("GET", request.URL.String(), nil) r.Header.Set("Authorization", request.Header.Get("Authorization")) r.Header.Set("Accept-Encoding", request.Header.Get("Accept-Encoding")) *request = *r } return &ReverseProxy{ Transport: moxy.NewTransport(), Director: director, Filters: filters, } }
//Pull Image from Registry or Hub depending on image name func Pull(imageName string) (Image, error) { image, err := Parse(imageName) if err != nil { return Image{}, err } logrus.Info("pulling image: ", image) mURI := fmt.Sprintf("%v/%v/manifests/%v", image.Registry, image.Name, image.Tag) client := httpclient.Get() request, err := http.NewRequest("GET", mURI, nil) response, err := client.Do(request) if err != nil { return Image{}, fmt.Errorf("retrieving manifest: %v", err) } if response.StatusCode == http.StatusUnauthorized { logrus.Info("Pull is Unauthorized") err := AuthenticateResponse(response, request) if err != nil { return Image{}, fmt.Errorf("authenticating: %v", err) } response, err = client.Do(request) if err != nil { return Image{}, fmt.Errorf("retrieving manifest: %v", err) } } body, err := ioutil.ReadAll(response.Body) if err != nil { return Image{}, fmt.Errorf("reading manifest body: %v", err) } if response.StatusCode != 200 { switch response.StatusCode { case http.StatusUnauthorized: return Image{}, xerrors.Unauthorized case http.StatusNotFound: return Image{}, xerrors.NotFound default: return Image{}, fmt.Errorf("%d - %s", response.StatusCode, string(body)) } } if err := image.parseManifest(body); err != nil { return Image{}, fmt.Errorf("parsing manifest: %v", err) } return image, nil }
func AuthenticateResponse(dockerResponse *http.Response, request *http.Request) error { bearerToken := BearerAuthParams(dockerResponse) url := bearerToken["realm"] + "?service=" + bearerToken["service"] if bearerToken["scope"] != "" { url += "&scope=" + bearerToken["scope"] } req, err := http.NewRequest("GET", url, nil) if err != nil { return err } l, err := config.GetLogin(request.URL.Host) if err != nil { return err } req.SetBasicAuth(l.Username, l.Password) response, err := httpclient.Get().Do(req) if err != nil { return err } if response.StatusCode == http.StatusUnauthorized { return xerrors.Unauthorized } if response.StatusCode != http.StatusOK { return fmt.Errorf("authentication server response: %v - %v", response.StatusCode, response.Status) } defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err != nil { return err } var tok token err = json.Unmarshal(body, &tok) if err != nil { return err } request.Header.Set("Authorization", "Bearer "+tok.String()) return nil }
func newSingleHostReverseProxy() *httputil.ReverseProxy { director := func(request *http.Request) { var validID = regexp.MustCompile(`.*/blobs/(.*)$`) u := request.URL.Path logrus.Debugf("request url: %v", u) if !validID.MatchString(u) { logrus.Errorf("cannot parse url: %v", u) } host, _ := database.GetRegistryMapping(validID.FindStringSubmatch(u)[1]) out, _ := url.Parse(host) request.URL.Scheme = out.Scheme request.URL.Host = out.Host client := httpclient.Get() req, _ := http.NewRequest("HEAD", request.URL.String(), nil) resp, err := client.Do(req) if err != nil { logrus.Errorf("response error: %v", err) return } if resp.StatusCode == http.StatusUnauthorized { logrus.Info("pull from clair is unauthorized") docker.AuthenticateResponse(resp, request) } r, _ := http.NewRequest("GET", request.URL.String(), nil) r.Header.Set("Authorization", request.Header.Get("Authorization")) r.Header.Set("Accept-Encoding", request.Header.Get("Accept-Encoding")) *request = *r } return &httputil.ReverseProxy{ Director: director, } }
encryptedPwd, err := bcrypt.GenerateFromPassword(pwd, 5) if err != nil { fmt.Println(xerrors.InternalError) logrus.Fatalf("encrypting password: %v", err) } usr.Password = string(encryptedPwd) users[reg] = usr s, err := xstrings.ToIndentJSON(users) if err != nil { fmt.Println(xerrors.InternalError) logrus.Fatalf("indenting login: %v", err) } ioutil.WriteFile(config.HyperclairConfig(), s, os.ModePerm) client := httpclient.Get() req, err := http.NewRequest("GET", HyperclairURI+"/login?realm="+reg, nil) if err != nil { fmt.Println(xerrors.InternalError) logrus.Fatalf("creating login request: %v", err) } req.SetBasicAuth(usr.Username, string(pwd)) resp, err := client.Do(req) if err != nil || (resp.StatusCode != http.StatusUnauthorized && resp.StatusCode != http.StatusOK) { fmt.Println(xerrors.InternalError) logrus.Fatalf("log in: %v", err) } if resp.StatusCode == http.StatusUnauthorized { fmt.Println("Unauthorized: Wrong login/password, please try again")