diff --git a/components/engine/api.go b/components/engine/api.go index 3c440d7331..60d3b632cb 100644 --- a/components/engine/api.go +++ b/components/engine/api.go @@ -66,48 +66,15 @@ func getBoolParam(value string) (bool, error) { return false, fmt.Errorf("Bad parameter") } -func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - // FIXME: Handle multiple login at once - // FIXME: return specific error code if config file missing? - authConfig, err := auth.LoadConfig(srv.runtime.root) - if err != nil { - if err != auth.ErrConfigFileMissing { - return err - } - authConfig = &auth.AuthConfig{} - } - b, err := json.Marshal(&auth.AuthConfig{Username: authConfig.Username, Email: authConfig.Email}) - if err != nil { - return err - } - writeJson(w, b) - return nil -} - func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - // FIXME: Handle multiple login at once - config := &auth.AuthConfig{} - if err := json.NewDecoder(r.Body).Decode(config); err != nil { + authConfig := &auth.AuthConfig{} + if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil { return err } - - authConfig, err := auth.LoadConfig(srv.runtime.root) - if err != nil { - if err != auth.ErrConfigFileMissing { - return err - } - authConfig = &auth.AuthConfig{} - } - if config.Username == authConfig.Username { - config.Password = authConfig.Password - } - - newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root) - status, err := auth.Login(newAuthConfig) + status, err := auth.Login(authConfig) if err != nil { return err } - if status != "" { b, err := json.Marshal(&ApiAuth{Status: status}) if err != nil { @@ -317,7 +284,9 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht if version > 1.0 { w.Header().Set("Content-Type", "application/json") } - if err := srv.ImagePull(image, tag, registry, w, version > 1.0); err != nil { + authConfig := &auth.AuthConfig{} + json.NewDecoder(r.Body).Decode(authConfig) + if err := srv.ImagePull(image, tag, registry, w, version > 1.0, authConfig); err != nil { return err } } else { //import @@ -371,6 +340,10 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht } func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + authConfig := &auth.AuthConfig{} + if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil { + return err + } if err := parseForm(r); err != nil { return err } @@ -381,7 +354,7 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http } name := vars["name"] - if err := srv.ImagePush(name, registry, w); err != nil { + if err := srv.ImagePush(name, registry, w, authConfig); err != nil { return err } return nil @@ -676,7 +649,6 @@ func ListenAndServe(addr string, srv *Server, logging bool) error { m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{ "GET": { - "/auth": getAuth, "/version": getVersion, "/info": getInfo, "/images/json": getImagesJson, diff --git a/components/engine/api_test.go b/components/engine/api_test.go index f364c6c895..b0f1444367 100644 --- a/components/engine/api_test.go +++ b/components/engine/api_test.go @@ -6,7 +6,6 @@ import ( "bytes" "encoding/json" "github.com/dotcloud/docker/auth" - "github.com/dotcloud/docker/registry" "github.com/dotcloud/docker/utils" "io" "net" @@ -18,7 +17,7 @@ import ( "time" ) -func TestGetAuth(t *testing.T) { +func TestPostAuth(t *testing.T) { runtime, err := newTestRuntime() if err != nil { t.Fatal(err) @@ -54,12 +53,6 @@ func TestGetAuth(t *testing.T) { if r.Code != http.StatusOK && r.Code != 0 { t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code) } - - newAuthConfig := registry.NewRegistry(runtime.root).GetAuthConfig(false) - if newAuthConfig.Username != authConfig.Username || - newAuthConfig.Email != authConfig.Email { - t.Fatalf("The auth configuration hasn't been set correctly") - } } func TestGetVersion(t *testing.T) { @@ -494,40 +487,6 @@ func TestGetContainersByName(t *testing.T) { } } -func TestPostAuth(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } - defer nuke(runtime) - - srv := &Server{ - runtime: runtime, - } - - config := &auth.AuthConfig{ - Username: "utest", - Email: "utest@yopmail.com", - } - - authStr := auth.EncodeAuth(config) - auth.SaveConfig(runtime.root, authStr, config.Email) - - r := httptest.NewRecorder() - if err := getAuth(srv, API_VERSION, r, nil, nil); err != nil { - t.Fatal(err) - } - - authConfig := &auth.AuthConfig{} - if err := json.Unmarshal(r.Body.Bytes(), authConfig); err != nil { - t.Fatal(err) - } - - if authConfig.Username != config.Username || authConfig.Email != config.Email { - t.Errorf("The retrieve auth mismatch with the one set.") - } -} - func TestPostCommit(t *testing.T) { runtime, err := newTestRuntime() if err != nil { diff --git a/components/engine/auth/auth.go b/components/engine/auth/auth.go index 9c34604419..5da0b30415 100644 --- a/components/engine/auth/auth.go +++ b/components/engine/auth/auth.go @@ -48,7 +48,7 @@ func IndexServerAddress() string { } // create a base64 encoded auth string to store in config -func EncodeAuth(authConfig *AuthConfig) string { +func encodeAuth(authConfig *AuthConfig) string { authStr := authConfig.Username + ":" + authConfig.Password msg := []byte(authStr) encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg))) @@ -57,7 +57,7 @@ func EncodeAuth(authConfig *AuthConfig) string { } // decode the auth string -func DecodeAuth(authStr string) (*AuthConfig, error) { +func decodeAuth(authStr string) (*AuthConfig, error) { decLen := base64.StdEncoding.DecodedLen(len(authStr)) decoded := make([]byte, decLen) authByte := []byte(authStr) @@ -82,7 +82,7 @@ func DecodeAuth(authStr string) (*AuthConfig, error) { func LoadConfig(rootPath string) (*AuthConfig, error) { confFile := path.Join(rootPath, CONFIGFILE) if _, err := os.Stat(confFile); err != nil { - return nil, ErrConfigFileMissing + return &AuthConfig{rootPath:rootPath}, ErrConfigFileMissing } b, err := ioutil.ReadFile(confFile) if err != nil { @@ -94,7 +94,7 @@ func LoadConfig(rootPath string) (*AuthConfig, error) { } origAuth := strings.Split(arr[0], " = ") origEmail := strings.Split(arr[1], " = ") - authConfig, err := DecodeAuth(origAuth[1]) + authConfig, err := decodeAuth(origAuth[1]) if err != nil { return nil, err } @@ -104,13 +104,13 @@ func LoadConfig(rootPath string) (*AuthConfig, error) { } // save the auth config -func SaveConfig(rootPath, authStr string, email string) error { - confFile := path.Join(rootPath, CONFIGFILE) - if len(email) == 0 { +func SaveConfig(authConfig *AuthConfig) error { + confFile := path.Join(authConfig.rootPath, CONFIGFILE) + if len(authConfig.Email) == 0 { os.Remove(confFile) return nil } - lines := "auth = " + authStr + "\n" + "email = " + email + "\n" + lines := "auth = " + encodeAuth(authConfig) + "\n" + "email = " + authConfig.Email + "\n" b := []byte(lines) err := ioutil.WriteFile(confFile, b, 0600) if err != nil { @@ -121,7 +121,6 @@ func SaveConfig(rootPath, authStr string, email string) error { // try to register/login to the registry server func Login(authConfig *AuthConfig) (string, error) { - storeConfig := false client := &http.Client{} reqStatusCode := 0 var status string @@ -147,7 +146,6 @@ func Login(authConfig *AuthConfig) (string, error) { if reqStatusCode == 201 { status = "Account created. Please use the confirmation link we sent" + " to your e-mail to activate it.\n" - storeConfig = true } else if reqStatusCode == 403 { return "", fmt.Errorf("Login: Your account hasn't been activated. " + "Please check your e-mail for a confirmation link.") @@ -166,11 +164,7 @@ func Login(authConfig *AuthConfig) (string, error) { } if resp.StatusCode == 200 { status = "Login Succeeded\n" - storeConfig = true } else if resp.StatusCode == 401 { - if err := SaveConfig(authConfig.rootPath, "", ""); err != nil { - return "", err - } return "", fmt.Errorf("Wrong login/password, please try again") } else { return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body, @@ -182,11 +176,5 @@ func Login(authConfig *AuthConfig) (string, error) { } else { return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody) } - if storeConfig { - authStr := EncodeAuth(authConfig) - if err := SaveConfig(authConfig.rootPath, authStr, authConfig.Email); err != nil { - return "", err - } - } return status, nil } diff --git a/components/engine/buildfile.go b/components/engine/buildfile.go index 23f2f47172..8a6d6305b0 100644 --- a/components/engine/buildfile.go +++ b/components/engine/buildfile.go @@ -63,7 +63,7 @@ func (b *buildFile) CmdFrom(name string) error { remote = name } - if err := b.srv.ImagePull(remote, tag, "", b.out, false); err != nil { + if err := b.srv.ImagePull(remote, tag, "", b.out, false, nil); err != nil { return err } diff --git a/components/engine/commands.go b/components/engine/commands.go index 97a249e54a..cbd276b455 100644 --- a/components/engine/commands.go +++ b/components/engine/commands.go @@ -279,27 +279,16 @@ func (cli *DockerCli) CmdLogin(args ...string) error { return nil } - body, _, err := cli.call("GET", "/auth", nil) - if err != nil { - return err - } - - var out auth.AuthConfig - err = json.Unmarshal(body, &out) - if err != nil { - return err - } - var username string var password string var email string - fmt.Print("Username (", out.Username, "): ") + fmt.Print("Username (", cli.authConfig.Username, "): ") username = readAndEchoString(os.Stdin, os.Stdout) if username == "" { - username = out.Username + username = cli.authConfig.Username } - if username != out.Username { + if username != cli.authConfig.Username { fmt.Print("Password: ") password = readString(os.Stdin, os.Stdout) @@ -307,20 +296,21 @@ func (cli *DockerCli) CmdLogin(args ...string) error { return fmt.Errorf("Error : Password Required") } - fmt.Print("Email (", out.Email, "): ") + fmt.Print("Email (", cli.authConfig.Email, "): ") email = readAndEchoString(os.Stdin, os.Stdout) if email == "" { - email = out.Email + email = cli.authConfig.Email } } else { - email = out.Email + email = cli.authConfig.Email } + term.RestoreTerminal(oldState) - out.Username = username - out.Password = password - out.Email = email + cli.authConfig.Username = username + cli.authConfig.Password = password + cli.authConfig.Email = email - body, _, err = cli.call("POST", "/auth", out) + body, _, err := cli.call("POST", "/auth", cli.authConfig) if err != nil { return err } @@ -328,10 +318,11 @@ func (cli *DockerCli) CmdLogin(args ...string) error { var out2 ApiAuth err = json.Unmarshal(body, &out2) if err != nil { + auth.LoadConfig(os.Getenv("HOME")) return err } + auth.SaveConfig(cli.authConfig) if out2.Status != "" { - term.RestoreTerminal(oldState) fmt.Print(out2.Status) } return nil @@ -688,13 +679,12 @@ func (cli *DockerCli) CmdPush(args ...string) error { return nil } - username, err := cli.checkIfLogged(*registry == "", "push") - if err != nil { + if err := cli.checkIfLogged(*registry == "", "push"); err != nil { return err } if len(strings.SplitN(name, "/", 2)) == 1 { - return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in / (ex: %s/%s)", username, name) + return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in / (ex: %s/%s)", cli.authConfig.Username, name) } v := url.Values{} @@ -726,7 +716,7 @@ func (cli *DockerCli) CmdPull(args ...string) error { } if strings.Contains(remote, "/") { - if _, err := cli.checkIfLogged(true, "pull"); err != nil { + if err := cli.checkIfLogged(true, "pull"); err != nil { return err } } @@ -1220,38 +1210,17 @@ func (cli *DockerCli) CmdRun(args ...string) error { return nil } -func (cli *DockerCli) checkIfLogged(condition bool, action string) (string, error) { - body, _, err := cli.call("GET", "/auth", nil) - if err != nil { - return "", err - } - - var out auth.AuthConfig - err = json.Unmarshal(body, &out) - if err != nil { - return "", err - } - +func (cli *DockerCli) checkIfLogged(condition bool, action string) error { // If condition AND the login failed - if condition && out.Username == "" { + if condition && cli.authConfig.Username == "" { if err := cli.CmdLogin(""); err != nil { - return "", err + return err } - - body, _, err = cli.call("GET", "/auth", nil) - if err != nil { - return "", err - } - err = json.Unmarshal(body, &out) - if err != nil { - return "", err - } - - if out.Username == "" { - return "", fmt.Errorf("Please login prior to %s. ('docker login')", action) + if cli.authConfig.Username == "" { + return fmt.Errorf("Please login prior to %s. ('docker login')", action) } } - return out.Username, nil + return nil } func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, error) { @@ -1435,10 +1404,12 @@ func Subcmd(name, signature, description string) *flag.FlagSet { } func NewDockerCli(addr string, port int) *DockerCli { - return &DockerCli{addr, port} + authConfig, _ := auth.LoadConfig(os.Getenv("HOME")) + return &DockerCli{addr, port, authConfig} } type DockerCli struct { - host string - port int + host string + port int + authConfig *auth.AuthConfig } diff --git a/components/engine/registry/registry.go b/components/engine/registry/registry.go index 36b01d643a..cc5e7496b9 100644 --- a/components/engine/registry/registry.go +++ b/components/engine/registry/registry.go @@ -466,10 +466,7 @@ type Registry struct { authConfig *auth.AuthConfig } -func NewRegistry(root string) *Registry { - // If the auth file does not exist, keep going - authConfig, _ := auth.LoadConfig(root) - +func NewRegistry(root string, authConfig *auth.AuthConfig) *Registry { r := &Registry{ authConfig: authConfig, client: &http.Client{}, diff --git a/components/engine/runtime_test.go b/components/engine/runtime_test.go index 384cbd1eb8..40f6425e78 100644 --- a/components/engine/runtime_test.go +++ b/components/engine/runtime_test.go @@ -65,7 +65,7 @@ func init() { runtime: runtime, } // Retrieve the Image - if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, false); err != nil { + if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, false, nil); err != nil { panic(err) } } diff --git a/components/engine/server.go b/components/engine/server.go index 0440b0a8a4..42726fb59c 100644 --- a/components/engine/server.go +++ b/components/engine/server.go @@ -50,7 +50,7 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error { func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) { - results, err := registry.NewRegistry(srv.runtime.root).SearchRepositories(term) + results, err := registry.NewRegistry(srv.runtime.root, nil).SearchRepositories(term) if err != nil { return nil, err } @@ -394,8 +394,8 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, a return nil } -func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, json bool) error { - r := registry.NewRegistry(srv.runtime.root) +func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, json bool, authConfig *auth.AuthConfig) error { + r := registry.NewRegistry(srv.runtime.root, authConfig) out = utils.NewWriteFlusher(out) if endpoint != "" { if err := srv.pullImage(r, out, name, endpoint, nil, json); err != nil { @@ -576,10 +576,10 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId, return nil } -func (srv *Server) ImagePush(name, endpoint string, out io.Writer) error { +func (srv *Server) ImagePush(name, endpoint string, out io.Writer, authConfig *auth.AuthConfig) error { out = utils.NewWriteFlusher(out) img, err := srv.runtime.graph.Get(name) - r := registry.NewRegistry(srv.runtime.root) + r := registry.NewRegistry(srv.runtime.root, authConfig) if err != nil { fmt.Fprintf(out, "The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name]))