diff --git a/api.go b/api.go index 0817dcc9cd..63698c81bb 100644 --- a/api.go +++ b/api.go @@ -13,7 +13,7 @@ import ( "strings" ) -const API_VERSION = 1.1 +const API_VERSION = 1.2 func hijackServer(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) { conn, _, err := w.(http.Hijacker).Hijack() @@ -68,15 +68,55 @@ func getBoolParam(value string) (bool, error) { return false, fmt.Errorf("Bad parameter") } -func postAuth(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 +func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { + if version > 1.1 { + w.WriteHeader(http.StatusNotFound) + return nil } - status, err := auth.Login(authConfig) + 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 { + authConfig := &auth.AuthConfig{} + err := json.NewDecoder(r.Body).Decode(authConfig) + if err != nil { + return err + } + status := "" + if version > 1.1 { + status, err = auth.Login(authConfig, false) + if err != nil { + return err + } + } else { + localAuthConfig, err := auth.LoadConfig(srv.runtime.root) + if err != nil { + if err != auth.ErrConfigFileMissing { + return err + } + } + if authConfig.Username == localAuthConfig.Username { + authConfig.Password = localAuthConfig.Password + } + + newAuthConfig := auth.NewAuthConfig(authConfig.Username, authConfig.Password, authConfig.Email, srv.runtime.root) + status, err = auth.Login(newAuthConfig, true) + if err != nil { + return err + } + } if status != "" { b, err := json.Marshal(&ApiAuth{Status: status}) if err != nil { @@ -288,7 +328,15 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht if image != "" { //pull registry := r.Form.Get("registry") authConfig := &auth.AuthConfig{} - json.NewDecoder(r.Body).Decode(authConfig) + if version > 1.1 { + json.NewDecoder(r.Body).Decode(authConfig) + } else { + localAuthConfig, err := auth.LoadConfig(srv.runtime.root) + if err != nil && err != auth.ErrConfigFileMissing { + return err + } + authConfig = localAuthConfig + } if err := srv.ImagePull(image, tag, registry, w, sf, authConfig); err != nil { if sf.Used() { w.Write(sf.FormatError(err)) @@ -358,8 +406,16 @@ 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 version > 1.1 { + if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil { + return err + } + } else { + localAuthConfig, err := auth.LoadConfig(srv.runtime.root) + if err != nil && err != auth.ErrConfigFileMissing { + return err + } + authConfig = localAuthConfig } if err := parseForm(r); err != nil { return err @@ -682,6 +738,7 @@ 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/auth/auth.go b/auth/auth.go index 5da0b30415..35bf024617 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -120,7 +120,8 @@ func SaveConfig(authConfig *AuthConfig) error { } // try to register/login to the registry server -func Login(authConfig *AuthConfig) (string, error) { +func Login(authConfig *AuthConfig, store bool) (string, error) { + storeConfig := false client := &http.Client{} reqStatusCode := 0 var status string @@ -146,6 +147,7 @@ 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.") @@ -164,7 +166,13 @@ func Login(authConfig *AuthConfig) (string, error) { } if resp.StatusCode == 200 { status = "Login Succeeded\n" + storeConfig = true } else if resp.StatusCode == 401 { + if store { + if err := SaveConfig(authConfig); err != nil { + return "", err + } + } return "", fmt.Errorf("Wrong login/password, please try again") } else { return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body, @@ -176,5 +184,10 @@ func Login(authConfig *AuthConfig) (string, error) { } else { return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody) } + if storeConfig && store { + if err := SaveConfig(authConfig); err != nil { + return "", err + } + } return status, nil } diff --git a/docs/sources/api/docker_remote_api.rst b/docs/sources/api/docker_remote_api.rst index 9087c21e1e..f6e2795857 100644 --- a/docs/sources/api/docker_remote_api.rst +++ b/docs/sources/api/docker_remote_api.rst @@ -14,12 +14,13 @@ Docker Remote API - The Remote API is replacing rcli - Default port in the docker deamon is 4243 - The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection is hijacked to transport stdout stdin and stderr +- Since API version 1.2, the auth configuration is now handled client side, so the client has to send the authConfig as POST in /images/create and /images//pull 2. Version ========== -The current verson of the API is 1.1 -Calling /images//insert is the same as calling /v1.1/images//insert +The current verson of the API is 1.2 +Calling /images//insert is the same as calling /v1.2/images//insert You can still call an old version of the api using /v1.0/images//insert 3. Endpoints @@ -550,12 +551,19 @@ Create an image Create an image, either by pull it from the registry or by importing it - **Example request**: + **Example request v1.0**: .. sourcecode:: http POST /images/create?fromImage=base HTTP/1.1 + **Example request v1.2**: + + .. sourcecode:: http + + POST /images/create?fromImage=base HTTP/1.1 + {{ authConfig }} + **Example response v1.1**: .. sourcecode:: http @@ -720,12 +728,19 @@ Push an image on the registry Push the image ``name`` on the registry - **Example request**: + **Example request v1.0**: .. sourcecode:: http POST /images/test/push HTTP/1.1 + **Example request v1.2**: + + .. sourcecode:: http + + POST /images/test/push HTTP/1.1 + {{ authConfig }} + **Example response v1.1**: .. sourcecode:: http @@ -875,7 +890,7 @@ Build an image from Dockerfile via stdin :statuscode 500: server error -Get default username and email +Get default username and email ****************************** .. http:get:: /auth @@ -904,8 +919,8 @@ Get default username and email :statuscode 500: server error -Set auth configuration -********************** +Check auth configuration (and store if if api < 1.2) +**************************************************** .. http:post:: /auth