func (graph *Graph) getHttpClient() *http.Client { if graph.httpClient == nil { graph.httpClient = &http.Client{} graph.httpClient.Jar = cookiejar.NewCookieJar() } return graph.httpClient }
func postAuth(srv *Server, w http.ResponseWriter, r *http.Request, vars map[string]string) ([]byte, error) { config := &auth.AuthConfig{} if err := json.NewDecoder(r.Body).Decode(config); err != nil { return nil, err } if config.Username == srv.runtime.authConfig.Username { config.Password = srv.runtime.authConfig.Password } newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root) status, err := auth.Login(newAuthConfig) if err != nil { return nil, err } else { srv.runtime.graph.getHttpClient().Jar = cookiejar.NewCookieJar() srv.runtime.authConfig = newAuthConfig } if status != "" { b, err := json.Marshal(&ApiAuth{Status: status}) if err != nil { return nil, err } return b, nil } w.WriteHeader(http.StatusNoContent) return nil, nil }
func NewRegistry(root string) *Registry { // If the auth file does not exist, keep going authConfig, _ := auth.LoadConfig(root) r := &Registry{ authConfig: authConfig, client: &http.Client{}, } r.client.Jar = cookiejar.NewCookieJar() return r }
func NewRegistry(root string, authConfig *auth.AuthConfig) *Registry { httpTransport := &http.Transport{ DisableKeepAlives: true, Proxy: http.ProxyFromEnvironment, } r := &Registry{ authConfig: authConfig, client: &http.Client{ Transport: httpTransport, }, } r.client.Jar = cookiejar.NewCookieJar() return r }
func NewRegistry(root string) *Registry { // If the auth file does not exist, keep going authConfig, _ := auth.LoadConfig(root) httpTransport := &http.Transport{ DisableKeepAlives: true, Proxy: http.ProxyFromEnvironment, } r := &Registry{ authConfig: authConfig, client: &http.Client{ Transport: httpTransport, }, } r.client.Jar = cookiejar.NewCookieJar() return r }
func (r *Registry) ResetClient(authConfig *auth.AuthConfig) { r.authConfig = authConfig r.client.Jar = cookiejar.NewCookieJar() }
// 'docker login': login / register a user to registry service. func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error { // Read a line on raw terminal with support for simple backspace // sequences and echo. // // This function is necessary because the login command must be done in a // raw terminal for two reasons: // - we have to read a password (without echoing it); // - the rcli "protocol" only supports cannonical and raw modes and you // can't tune it once the command as been started. var readStringOnRawTerminal = func(stdin io.Reader, stdout io.Writer, echo bool) string { char := make([]byte, 1) buffer := make([]byte, 64) var i = 0 for i < len(buffer) { n, err := stdin.Read(char) if n > 0 { if char[0] == '\r' || char[0] == '\n' { stdout.Write([]byte{'\r', '\n'}) break } else if char[0] == 127 || char[0] == '\b' { if i > 0 { if echo { stdout.Write([]byte{'\b', ' ', '\b'}) } i-- } } else if !unicode.IsSpace(rune(char[0])) && !unicode.IsControl(rune(char[0])) { if echo { stdout.Write(char) } buffer[i] = char[0] i++ } } if err != nil { if err != io.EOF { fmt.Fprintf(stdout, "Read error: %v\r\n", err) } break } } return string(buffer[:i]) } var readAndEchoString = func(stdin io.Reader, stdout io.Writer) string { return readStringOnRawTerminal(stdin, stdout, true) } var readString = func(stdin io.Reader, stdout io.Writer) string { return readStringOnRawTerminal(stdin, stdout, false) } stdout.SetOptionRawTerminal() cmd := rcli.Subcmd(stdout, "login", "", "Register or Login to the docker registry server") if err := cmd.Parse(args); err != nil { return nil } var username string var password string var email string fmt.Fprint(stdout, "Username (", srv.runtime.authConfig.Username, "): ") username = readAndEchoString(stdin, stdout) if username == "" { username = srv.runtime.authConfig.Username } if username != srv.runtime.authConfig.Username { fmt.Fprint(stdout, "Password: "******"" { return fmt.Errorf("Error : Password Required") } fmt.Fprint(stdout, "Email (", srv.runtime.authConfig.Email, "): ") email = readAndEchoString(stdin, stdout) if email == "" { email = srv.runtime.authConfig.Email } } else { password = srv.runtime.authConfig.Password email = srv.runtime.authConfig.Email } newAuthConfig := auth.NewAuthConfig(username, password, email, srv.runtime.root) status, err := auth.Login(newAuthConfig) if err != nil { fmt.Fprintf(stdout, "Error: %s\r\n", err) } else { srv.runtime.graph.getHttpClient().Jar = cookiejar.NewCookieJar() srv.runtime.authConfig = newAuthConfig } if status != "" { fmt.Fprint(stdout, status) } return nil }
// Push a repository to the registry. // Remote has the format '<user>/<repo> func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Repository, authConfig *auth.AuthConfig) error { client := graph.getHttpClient() // FIXME: Do not reset the cookie each time? (need to reset it in case updating latest of a repo and repushing) client.Jar = cookiejar.NewCookieJar() var imgList []*ImgListJson fmt.Fprintf(stdout, "Processing checksums\n") imageSet := make(map[string]struct{}) for tag, id := range localRepo { img, err := graph.Get(id) if err != nil { return err } img.WalkHistory(func(img *Image) error { if _, exists := imageSet[img.Id]; exists { return nil } imageSet[img.Id] = struct{}{} checksum, err := graph.getChecksum(img.Id) if err != nil { return err } imgList = append([]*ImgListJson{{ Id: img.Id, Checksum: checksum, tag: tag, }}, imgList...) return nil }) } imgListJson, err := json.Marshal(imgList) if err != nil { return err } Debugf("json sent: %s\n", imgListJson) fmt.Fprintf(stdout, "Sending image list\n") req, err := http.NewRequest("PUT", INDEX_ENDPOINT+"/repositories/"+remote+"/", bytes.NewReader(imgListJson)) if err != nil { return err } req.SetBasicAuth(authConfig.Username, authConfig.Password) req.ContentLength = int64(len(imgListJson)) req.Header.Set("X-Docker-Token", "true") res, err := client.Do(req) if err != nil { return err } defer res.Body.Close() for res.StatusCode >= 300 && res.StatusCode < 400 { Debugf("Redirected to %s\n", res.Header.Get("Location")) req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJson)) if err != nil { return err } req.SetBasicAuth(authConfig.Username, authConfig.Password) req.ContentLength = int64(len(imgListJson)) req.Header.Set("X-Docker-Token", "true") res, err = client.Do(req) if err != nil { return err } defer res.Body.Close() } if res.StatusCode != 200 && res.StatusCode != 201 { errBody, err := ioutil.ReadAll(res.Body) if err != nil { return err } return fmt.Errorf("Error: Status %d trying to push repository %s: %s", res.StatusCode, remote, errBody) } var token, endpoints []string if res.Header.Get("X-Docker-Token") != "" { token = res.Header["X-Docker-Token"] Debugf("Auth token: %v", token) } else { return fmt.Errorf("Index response didn't contain an access token") } if res.Header.Get("X-Docker-Endpoints") != "" { endpoints = res.Header["X-Docker-Endpoints"] } else { return fmt.Errorf("Index response didn't contain any endpoints") } // FIXME: Send only needed images for _, registry := range endpoints { fmt.Fprintf(stdout, "Pushing repository %s to %s (%d tags)\r\n", remote, registry, len(localRepo)) // For each image within the repo, push them for _, elem := range imgList { if err := graph.pushPrimitive(stdout, remote, elem.tag, elem.Id, registry, token); err != nil { // FIXME: Continue on error? return err } } } req2, err := http.NewRequest("PUT", INDEX_ENDPOINT+"/repositories/"+remote+"/images", bytes.NewReader(imgListJson)) if err != nil { return err } req2.SetBasicAuth(authConfig.Username, authConfig.Password) req2.Header["X-Docker-Endpoints"] = endpoints req2.ContentLength = int64(len(imgListJson)) res2, err := client.Do(req2) if err != nil { return err } defer res2.Body.Close() if res2.StatusCode != 204 { if errBody, err := ioutil.ReadAll(res2.Body); err != nil { return err } else { return fmt.Errorf("Error: Status %d trying to push checksums %s: %s", res2.StatusCode, remote, errBody) } } return nil }