Prechádzať zdrojové kódy

move auth to the client WIP

Victor Vieux 12 rokov pred
rodič
commit
49e656839f
8 zmenil súbory, kde vykonal 55 pridanie a 168 odobranie
  1. 11 39
      api.go
  2. 1 42
      api_test.go
  3. 8 20
      auth/auth.go
  4. 1 1
      buildfile.go
  5. 27 56
      commands.go
  6. 1 4
      registry/registry.go
  7. 1 1
      runtime_test.go
  8. 5 5
      server.go

+ 11 - 39
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,

+ 1 - 42
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 {

+ 8 - 20
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
 }

+ 1 - 1
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
 			}
 

+ 27 - 56
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 <user>/<repo> (ex: %s/%s)", username, name)
+		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (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
-		}
-
-		body, _, err = cli.call("GET", "/auth", nil)
-		if err != nil {
-			return "", err
-		}
-		err = json.Unmarshal(body, &out)
-		if err != nil {
-			return "", err
+			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
 }

+ 1 - 4
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{},

+ 1 - 1
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)
 	}
 }

+ 5 - 5
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]))