From c72ff318d3fb6ab887af21cf4410e1bc8104663a Mon Sep 17 00:00:00 2001 From: creack Date: Fri, 22 Mar 2013 02:19:39 -0700 Subject: [PATCH] Integrate Auth in runtime and make the config file relative to runtime root --- .gitignore | 1 + auth/auth.go | 62 ++++++++++++++++++++++++++--------------------- auth/auth_test.go | 2 +- commands.go | 25 +++++++------------ registry.go | 8 ++---- runtime.go | 8 ++++++ 6 files changed, 55 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index a9b5777c6d..eba48d297e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ build_src command-line-arguments.test .flymake* docker.test +auth/auth.test diff --git a/auth/auth.go b/auth/auth.go index 2a3d1a439f..2779ae04c4 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -8,11 +8,12 @@ import ( "io/ioutil" "net/http" "os" + "path" "strings" ) // Where we store the config file -const CONFIGFILE = "/var/lib/docker/.dockercfg" +const CONFIGFILE = ".dockercfg" // the registry server we want to login against //const REGISTRY_SERVER = "https://registry.docker.io" @@ -22,10 +23,11 @@ type AuthConfig struct { Username string `json:"username"` Password string `json:"password"` Email string `json:"email"` + rootPath string `json:-` } // 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))) @@ -34,50 +36,54 @@ 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) n, err := base64.StdEncoding.Decode(decoded, authByte) if err != nil { - return AuthConfig{}, err + return nil, err } if n > decLen { - return AuthConfig{}, errors.New("something went wrong decoding auth config") + return nil, fmt.Errorf("Something went wrong decoding auth config") } arr := strings.Split(string(decoded), ":") + if len(arr) != 2 { + return nil, fmt.Errorf("Invalid auth configuration file") + } password := strings.Trim(arr[1], "\x00") - return AuthConfig{Username: arr[0], Password: password}, nil + return &AuthConfig{Username: arr[0], Password: password}, nil } // load up the auth config information and return values -func LoadConfig() (AuthConfig, error) { - if _, err := os.Stat(CONFIGFILE); err == nil { - b, err := ioutil.ReadFile(CONFIGFILE) - if err != nil { - return AuthConfig{}, err - } - arr := strings.Split(string(b), "\n") - orig_auth := strings.Split(arr[0], " = ") - orig_email := strings.Split(arr[1], " = ") - authConfig, err := DecodeAuth(orig_auth[1]) - if err != nil { - return AuthConfig{}, err - } - authConfig.Email = orig_email[1] - return authConfig, nil - } else { - return AuthConfig{}, nil +// FIXME: use the internal golang config parser +func LoadConfig(rootPath string) (*AuthConfig, error) { + confFile := path.Join(rootPath, CONFIGFILE) + if _, err := os.Stat(confFile); err != nil { + return &AuthConfig{}, fmt.Errorf("The Auth config file is missing") } - return AuthConfig{}, nil + b, err := ioutil.ReadFile(confFile) + if err != nil { + return nil, err + } + arr := strings.Split(string(b), "\n") + orig_auth := strings.Split(arr[0], " = ") + orig_email := strings.Split(arr[1], " = ") + authConfig, err := DecodeAuth(orig_auth[1]) + if err != nil { + return nil, err + } + authConfig.Email = orig_email[1] + authConfig.rootPath = rootPath + return authConfig, nil } // save the auth config -func saveConfig(authStr string, email string) error { +func saveConfig(rootPath, authStr string, email string) error { lines := "auth = " + authStr + "\n" + "email = " + email + "\n" b := []byte(lines) - err := ioutil.WriteFile(CONFIGFILE, b, 0600) + err := ioutil.WriteFile(path.Join(rootPath, CONFIGFILE), b, 0600) if err != nil { return err } @@ -85,7 +91,7 @@ func saveConfig(authStr string, email string) error { } // try to register/login to the registry server -func Login(authConfig AuthConfig) (string, error) { +func Login(authConfig *AuthConfig) (string, error) { storeConfig := false reqStatusCode := 0 var status string @@ -146,7 +152,7 @@ func Login(authConfig AuthConfig) (string, error) { } if storeConfig { authStr := EncodeAuth(authConfig) - saveConfig(authStr, authConfig.Email) + saveConfig(authConfig.rootPath, authStr, authConfig.Email) } return status, nil } diff --git a/auth/auth_test.go b/auth/auth_test.go index d1650668e7..ca584f9314 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -5,7 +5,7 @@ import ( ) func TestEncodeAuth(t *testing.T) { - newAuthConfig := AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"} + newAuthConfig := &AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"} authStr := EncodeAuth(newAuthConfig) decAuthConfig, err := DecodeAuth(authStr) if err != nil { diff --git a/commands.go b/commands.go index 9716c6d3da..1a588b2586 100644 --- a/commands.go +++ b/commands.go @@ -69,17 +69,13 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout io.Writer, args ...strin var username string var password string var email string - authConfig, err := auth.LoadConfig() - if err != nil { - fmt.Fprintf(stdout, "Error : %s\n", err) - } - fmt.Fprint(stdout, "Username (", authConfig.Username, "): ") + fmt.Fprint(stdout, "Username (", srv.runtime.authConfig.Username, "): ") fmt.Fscanf(stdin, "%s", &username) if username == "" { - username = authConfig.Username + username = srv.runtime.authConfig.Username } - if username != authConfig.Username { + if username != srv.runtime.authConfig.Username { fmt.Fprint(stdout, "Password: ") fmt.Fscanf(stdin, "%s", &password) @@ -87,16 +83,16 @@ func (srv *Server) CmdLogin(stdin io.ReadCloser, stdout io.Writer, args ...strin return errors.New("Error : Password Required\n") } - fmt.Fprint(stdout, "Email (", authConfig.Email, "): ") + fmt.Fprint(stdout, "Email (", srv.runtime.authConfig.Email, "): ") fmt.Fscanf(stdin, "%s", &email) if email == "" { - email = authConfig.Email + email = srv.runtime.authConfig.Email } } else { - password = authConfig.Password - email = authConfig.Email + password = srv.runtime.authConfig.Password + email = srv.runtime.authConfig.Email } - newAuthConfig := auth.AuthConfig{Username: username, Password: password, Email: email} + newAuthConfig := &auth.AuthConfig{Username: username, Password: password, Email: email} status, err := auth.Login(newAuthConfig) if err != nil { fmt.Fprintf(stdout, "Error : %s\n", err) @@ -473,7 +469,7 @@ func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string return fmt.Errorf("Not loggin and no user specified\n") } // FIXME: Allow pull repo:tag - return srv.runtime.graph.PullRepository(*user, cmd.Arg(0), "", srv.runtime.repositories) + return srv.runtime.graph.PullRepository(*user, cmd.Arg(0), "", srv.runtime.repositories, srv.runtime.authConfig) } func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error { @@ -867,9 +863,6 @@ func NewServer() (*Server, error) { if runtime.GOARCH != "amd64" { log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH) } - // if err != nil { - // return nil, err - // } runtime, err := NewRuntime() if err != nil { return nil, err diff --git a/registry.go b/registry.go index 5a80c8eb78..faef6f4e4c 100644 --- a/registry.go +++ b/registry.go @@ -129,19 +129,15 @@ func (graph *Graph) PullImage(imgId string) error { } // FIXME: Handle the askedTag parameter -func (graph *Graph) PullRepository(user, repoName, askedTag string, repositories *TagStore) error { +func (graph *Graph) PullRepository(user, repoName, askedTag string, repositories *TagStore, authConfig *auth.AuthConfig) error { client := &http.Client{} req, err := http.NewRequest("GET", REGISTRY_ENDPOINT+"/users/"+user+"/"+repoName, nil) if err != nil { return err } - authStruct, err := auth.LoadConfig() - if err != nil { - return err - } - req.SetBasicAuth(authStruct.Username, authStruct.Password) + req.SetBasicAuth(authConfig.Username, authConfig.Password) res, err := client.Do(req) if err != nil { return err diff --git a/runtime.go b/runtime.go index 3b16479f3c..bb59c7787a 100644 --- a/runtime.go +++ b/runtime.go @@ -3,6 +3,7 @@ package docker import ( "container/list" "fmt" + "github.com/dotcloud/docker/auth" "io" "io/ioutil" "log" @@ -20,6 +21,7 @@ type Runtime struct { networkManager *NetworkManager graph *Graph repositories *TagStore + authConfig *auth.AuthConfig } var sysInitPath string @@ -246,6 +248,11 @@ func NewRuntimeFromDirectory(root string) (*Runtime, error) { if err != nil { return nil, err } + authConfig, err := auth.LoadConfig(root) + if err != nil && authConfig == nil { + // If the auth file does not exist, keep going + return nil, err + } runtime := &Runtime{ root: root, @@ -254,6 +261,7 @@ func NewRuntimeFromDirectory(root string) (*Runtime, error) { networkManager: netManager, graph: g, repositories: repositories, + authConfig: authConfig, } if err := runtime.restore(); err != nil {