Browse code

move auth to the client WIP

Victor Vieux authored on 2013/05/31 00:39:43
Showing 8 changed files
... ...
@@ -66,48 +66,15 @@ func getBoolParam(value string) (bool, error) {
66 66
 	return false, fmt.Errorf("Bad parameter")
67 67
 }
68 68
 
69
-func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
70
-	// FIXME: Handle multiple login at once
71
-	// FIXME: return specific error code if config file missing?
72
-	authConfig, err := auth.LoadConfig(srv.runtime.root)
73
-	if err != nil {
74
-		if err != auth.ErrConfigFileMissing {
75
-			return err
76
-		}
77
-		authConfig = &auth.AuthConfig{}
78
-	}
79
-	b, err := json.Marshal(&auth.AuthConfig{Username: authConfig.Username, Email: authConfig.Email})
80
-	if err != nil {
81
-		return err
82
-	}
83
-	writeJson(w, b)
84
-	return nil
85
-}
86
-
87 69
 func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
88
-	// FIXME: Handle multiple login at once
89
-	config := &auth.AuthConfig{}
90
-	if err := json.NewDecoder(r.Body).Decode(config); err != nil {
70
+	authConfig := &auth.AuthConfig{}
71
+	if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
91 72
 		return err
92 73
 	}
93
-
94
-	authConfig, err := auth.LoadConfig(srv.runtime.root)
95
-	if err != nil {
96
-		if err != auth.ErrConfigFileMissing {
97
-			return err
98
-		}
99
-		authConfig = &auth.AuthConfig{}
100
-	}
101
-	if config.Username == authConfig.Username {
102
-		config.Password = authConfig.Password
103
-	}
104
-
105
-	newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root)
106
-	status, err := auth.Login(newAuthConfig)
74
+	status, err := auth.Login(authConfig)
107 75
 	if err != nil {
108 76
 		return err
109 77
 	}
110
-
111 78
 	if status != "" {
112 79
 		b, err := json.Marshal(&ApiAuth{Status: status})
113 80
 		if err != nil {
... ...
@@ -317,7 +284,9 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht
317 317
 		if version > 1.0 {
318 318
 			w.Header().Set("Content-Type", "application/json")
319 319
 		}
320
-		if err := srv.ImagePull(image, tag, registry, w, version > 1.0); err != nil {
320
+		authConfig := &auth.AuthConfig{}
321
+		json.NewDecoder(r.Body).Decode(authConfig)
322
+		if err := srv.ImagePull(image, tag, registry, w, version > 1.0, authConfig); err != nil {
321 323
 			return err
322 324
 		}
323 325
 	} else { //import
... ...
@@ -371,6 +340,10 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
371 371
 }
372 372
 
373 373
 func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
374
+	authConfig := &auth.AuthConfig{}
375
+	if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
376
+		return err
377
+	}
374 378
 	if err := parseForm(r); err != nil {
375 379
 		return err
376 380
 	}
... ...
@@ -381,7 +354,7 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
381 381
 	}
382 382
 	name := vars["name"]
383 383
 
384
-	if err := srv.ImagePush(name, registry, w); err != nil {
384
+	if err := srv.ImagePush(name, registry, w, authConfig); err != nil {
385 385
 		return err
386 386
 	}
387 387
 	return nil
... ...
@@ -676,7 +649,6 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
676 676
 
677 677
 	m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{
678 678
 		"GET": {
679
-			"/auth":                         getAuth,
680 679
 			"/version":                      getVersion,
681 680
 			"/info":                         getInfo,
682 681
 			"/images/json":                  getImagesJson,
... ...
@@ -6,7 +6,6 @@ import (
6 6
 	"bytes"
7 7
 	"encoding/json"
8 8
 	"github.com/dotcloud/docker/auth"
9
-	"github.com/dotcloud/docker/registry"
10 9
 	"github.com/dotcloud/docker/utils"
11 10
 	"io"
12 11
 	"net"
... ...
@@ -18,7 +17,7 @@ import (
18 18
 	"time"
19 19
 )
20 20
 
21
-func TestGetAuth(t *testing.T) {
21
+func TestPostAuth(t *testing.T) {
22 22
 	runtime, err := newTestRuntime()
23 23
 	if err != nil {
24 24
 		t.Fatal(err)
... ...
@@ -54,12 +53,6 @@ func TestGetAuth(t *testing.T) {
54 54
 	if r.Code != http.StatusOK && r.Code != 0 {
55 55
 		t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code)
56 56
 	}
57
-
58
-	newAuthConfig := registry.NewRegistry(runtime.root).GetAuthConfig(false)
59
-	if newAuthConfig.Username != authConfig.Username ||
60
-		newAuthConfig.Email != authConfig.Email {
61
-		t.Fatalf("The auth configuration hasn't been set correctly")
62
-	}
63 57
 }
64 58
 
65 59
 func TestGetVersion(t *testing.T) {
... ...
@@ -494,40 +487,6 @@ func TestGetContainersByName(t *testing.T) {
494 494
 	}
495 495
 }
496 496
 
497
-func TestPostAuth(t *testing.T) {
498
-	runtime, err := newTestRuntime()
499
-	if err != nil {
500
-		t.Fatal(err)
501
-	}
502
-	defer nuke(runtime)
503
-
504
-	srv := &Server{
505
-		runtime: runtime,
506
-	}
507
-
508
-	config := &auth.AuthConfig{
509
-		Username: "utest",
510
-		Email:    "utest@yopmail.com",
511
-	}
512
-
513
-	authStr := auth.EncodeAuth(config)
514
-	auth.SaveConfig(runtime.root, authStr, config.Email)
515
-
516
-	r := httptest.NewRecorder()
517
-	if err := getAuth(srv, API_VERSION, r, nil, nil); err != nil {
518
-		t.Fatal(err)
519
-	}
520
-
521
-	authConfig := &auth.AuthConfig{}
522
-	if err := json.Unmarshal(r.Body.Bytes(), authConfig); err != nil {
523
-		t.Fatal(err)
524
-	}
525
-
526
-	if authConfig.Username != config.Username || authConfig.Email != config.Email {
527
-		t.Errorf("The retrieve auth mismatch with the one set.")
528
-	}
529
-}
530
-
531 497
 func TestPostCommit(t *testing.T) {
532 498
 	runtime, err := newTestRuntime()
533 499
 	if err != nil {
... ...
@@ -48,7 +48,7 @@ func IndexServerAddress() string {
48 48
 }
49 49
 
50 50
 // create a base64 encoded auth string to store in config
51
-func EncodeAuth(authConfig *AuthConfig) string {
51
+func encodeAuth(authConfig *AuthConfig) string {
52 52
 	authStr := authConfig.Username + ":" + authConfig.Password
53 53
 	msg := []byte(authStr)
54 54
 	encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
... ...
@@ -57,7 +57,7 @@ func EncodeAuth(authConfig *AuthConfig) string {
57 57
 }
58 58
 
59 59
 // decode the auth string
60
-func DecodeAuth(authStr string) (*AuthConfig, error) {
60
+func decodeAuth(authStr string) (*AuthConfig, error) {
61 61
 	decLen := base64.StdEncoding.DecodedLen(len(authStr))
62 62
 	decoded := make([]byte, decLen)
63 63
 	authByte := []byte(authStr)
... ...
@@ -82,7 +82,7 @@ func DecodeAuth(authStr string) (*AuthConfig, error) {
82 82
 func LoadConfig(rootPath string) (*AuthConfig, error) {
83 83
 	confFile := path.Join(rootPath, CONFIGFILE)
84 84
 	if _, err := os.Stat(confFile); err != nil {
85
-		return nil, ErrConfigFileMissing
85
+		return &AuthConfig{rootPath:rootPath}, ErrConfigFileMissing
86 86
 	}
87 87
 	b, err := ioutil.ReadFile(confFile)
88 88
 	if err != nil {
... ...
@@ -94,7 +94,7 @@ func LoadConfig(rootPath string) (*AuthConfig, error) {
94 94
 	}
95 95
 	origAuth := strings.Split(arr[0], " = ")
96 96
 	origEmail := strings.Split(arr[1], " = ")
97
-	authConfig, err := DecodeAuth(origAuth[1])
97
+	authConfig, err := decodeAuth(origAuth[1])
98 98
 	if err != nil {
99 99
 		return nil, err
100 100
 	}
... ...
@@ -104,13 +104,13 @@ func LoadConfig(rootPath string) (*AuthConfig, error) {
104 104
 }
105 105
 
106 106
 // save the auth config
107
-func SaveConfig(rootPath, authStr string, email string) error {
108
-	confFile := path.Join(rootPath, CONFIGFILE)
109
-	if len(email) == 0 {
107
+func SaveConfig(authConfig *AuthConfig) error {
108
+	confFile := path.Join(authConfig.rootPath, CONFIGFILE)
109
+	if len(authConfig.Email) == 0 {
110 110
 		os.Remove(confFile)
111 111
 		return nil
112 112
 	}
113
-	lines := "auth = " + authStr + "\n" + "email = " + email + "\n"
113
+	lines := "auth = " + encodeAuth(authConfig) + "\n" + "email = " + authConfig.Email + "\n"
114 114
 	b := []byte(lines)
115 115
 	err := ioutil.WriteFile(confFile, b, 0600)
116 116
 	if err != nil {
... ...
@@ -121,7 +121,6 @@ func SaveConfig(rootPath, authStr string, email string) error {
121 121
 
122 122
 // try to register/login to the registry server
123 123
 func Login(authConfig *AuthConfig) (string, error) {
124
-	storeConfig := false
125 124
 	client := &http.Client{}
126 125
 	reqStatusCode := 0
127 126
 	var status string
... ...
@@ -147,7 +146,6 @@ func Login(authConfig *AuthConfig) (string, error) {
147 147
 	if reqStatusCode == 201 {
148 148
 		status = "Account created. Please use the confirmation link we sent" +
149 149
 			" to your e-mail to activate it.\n"
150
-		storeConfig = true
151 150
 	} else if reqStatusCode == 403 {
152 151
 		return "", fmt.Errorf("Login: Your account hasn't been activated. " +
153 152
 			"Please check your e-mail for a confirmation link.")
... ...
@@ -166,11 +164,7 @@ func Login(authConfig *AuthConfig) (string, error) {
166 166
 			}
167 167
 			if resp.StatusCode == 200 {
168 168
 				status = "Login Succeeded\n"
169
-				storeConfig = true
170 169
 			} else if resp.StatusCode == 401 {
171
-				if err := SaveConfig(authConfig.rootPath, "", ""); err != nil {
172
-					return "", err
173
-				}
174 170
 				return "", fmt.Errorf("Wrong login/password, please try again")
175 171
 			} else {
176 172
 				return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
... ...
@@ -182,11 +176,5 @@ func Login(authConfig *AuthConfig) (string, error) {
182 182
 	} else {
183 183
 		return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody)
184 184
 	}
185
-	if storeConfig {
186
-		authStr := EncodeAuth(authConfig)
187
-		if err := SaveConfig(authConfig.rootPath, authStr, authConfig.Email); err != nil {
188
-			return "", err
189
-		}
190
-	}
191 185
 	return status, nil
192 186
 }
... ...
@@ -63,7 +63,7 @@ func (b *buildFile) CmdFrom(name string) error {
63 63
 				remote = name
64 64
 			}
65 65
 
66
-			if err := b.srv.ImagePull(remote, tag, "", b.out, false); err != nil {
66
+			if err := b.srv.ImagePull(remote, tag, "", b.out, false, nil); err != nil {
67 67
 				return err
68 68
 			}
69 69
 
... ...
@@ -279,27 +279,16 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
279 279
 		return nil
280 280
 	}
281 281
 
282
-	body, _, err := cli.call("GET", "/auth", nil)
283
-	if err != nil {
284
-		return err
285
-	}
286
-
287
-	var out auth.AuthConfig
288
-	err = json.Unmarshal(body, &out)
289
-	if err != nil {
290
-		return err
291
-	}
292
-
293 282
 	var username string
294 283
 	var password string
295 284
 	var email string
296 285
 
297
-	fmt.Print("Username (", out.Username, "): ")
286
+	fmt.Print("Username (", cli.authConfig.Username, "): ")
298 287
 	username = readAndEchoString(os.Stdin, os.Stdout)
299 288
 	if username == "" {
300
-		username = out.Username
289
+		username = cli.authConfig.Username
301 290
 	}
302
-	if username != out.Username {
291
+	if username != cli.authConfig.Username {
303 292
 		fmt.Print("Password: ")
304 293
 		password = readString(os.Stdin, os.Stdout)
305 294
 
... ...
@@ -307,20 +296,21 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
307 307
 			return fmt.Errorf("Error : Password Required")
308 308
 		}
309 309
 
310
-		fmt.Print("Email (", out.Email, "): ")
310
+		fmt.Print("Email (", cli.authConfig.Email, "): ")
311 311
 		email = readAndEchoString(os.Stdin, os.Stdout)
312 312
 		if email == "" {
313
-			email = out.Email
313
+			email = cli.authConfig.Email
314 314
 		}
315 315
 	} else {
316
-		email = out.Email
316
+		email = cli.authConfig.Email
317 317
 	}
318
+	term.RestoreTerminal(oldState)
318 319
 
319
-	out.Username = username
320
-	out.Password = password
321
-	out.Email = email
320
+	cli.authConfig.Username = username
321
+	cli.authConfig.Password = password
322
+	cli.authConfig.Email = email
322 323
 
323
-	body, _, err = cli.call("POST", "/auth", out)
324
+	body, _, err := cli.call("POST", "/auth", cli.authConfig)
324 325
 	if err != nil {
325 326
 		return err
326 327
 	}
... ...
@@ -328,10 +318,11 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
328 328
 	var out2 ApiAuth
329 329
 	err = json.Unmarshal(body, &out2)
330 330
 	if err != nil {
331
+		auth.LoadConfig(os.Getenv("HOME"))
331 332
 		return err
332 333
 	}
334
+	auth.SaveConfig(cli.authConfig)
333 335
 	if out2.Status != "" {
334
-		term.RestoreTerminal(oldState)
335 336
 		fmt.Print(out2.Status)
336 337
 	}
337 338
 	return nil
... ...
@@ -688,13 +679,12 @@ func (cli *DockerCli) CmdPush(args ...string) error {
688 688
 		return nil
689 689
 	}
690 690
 
691
-	username, err := cli.checkIfLogged(*registry == "", "push")
692
-	if err != nil {
691
+	if err := cli.checkIfLogged(*registry == "", "push"); err != nil {
693 692
 		return err
694 693
 	}
695 694
 
696 695
 	if len(strings.SplitN(name, "/", 2)) == 1 {
697
-		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", username, name)
696
+		return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.authConfig.Username, name)
698 697
 	}
699 698
 
700 699
 	v := url.Values{}
... ...
@@ -726,7 +716,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
726 726
 	}
727 727
 
728 728
 	if strings.Contains(remote, "/") {
729
-		if _, err := cli.checkIfLogged(true, "pull"); err != nil {
729
+		if err := cli.checkIfLogged(true, "pull"); err != nil {
730 730
 			return err
731 731
 		}
732 732
 	}
... ...
@@ -1220,38 +1210,17 @@ func (cli *DockerCli) CmdRun(args ...string) error {
1220 1220
 	return nil
1221 1221
 }
1222 1222
 
1223
-func (cli *DockerCli) checkIfLogged(condition bool, action string) (string, error) {
1224
-	body, _, err := cli.call("GET", "/auth", nil)
1225
-	if err != nil {
1226
-		return "", err
1227
-	}
1228
-
1229
-	var out auth.AuthConfig
1230
-	err = json.Unmarshal(body, &out)
1231
-	if err != nil {
1232
-		return "", err
1233
-	}
1234
-
1223
+func (cli *DockerCli) checkIfLogged(condition bool, action string) error {
1235 1224
 	// If condition AND the login failed
1236
-	if condition && out.Username == "" {
1225
+	if condition && cli.authConfig.Username == "" {
1237 1226
 		if err := cli.CmdLogin(""); err != nil {
1238
-			return "", err
1239
-		}
1240
-
1241
-		body, _, err = cli.call("GET", "/auth", nil)
1242
-		if err != nil {
1243
-			return "", err
1244
-		}
1245
-		err = json.Unmarshal(body, &out)
1246
-		if err != nil {
1247
-			return "", err
1227
+			return err
1248 1228
 		}
1249
-
1250
-		if out.Username == "" {
1251
-			return "", fmt.Errorf("Please login prior to %s. ('docker login')", action)
1229
+		if cli.authConfig.Username == "" {
1230
+			return fmt.Errorf("Please login prior to %s. ('docker login')", action)
1252 1231
 		}
1253 1232
 	}
1254
-	return out.Username, nil
1233
+	return nil
1255 1234
 }
1256 1235
 
1257 1236
 func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, error) {
... ...
@@ -1435,10 +1404,12 @@ func Subcmd(name, signature, description string) *flag.FlagSet {
1435 1435
 }
1436 1436
 
1437 1437
 func NewDockerCli(addr string, port int) *DockerCli {
1438
-	return &DockerCli{addr, port}
1438
+	authConfig, _ := auth.LoadConfig(os.Getenv("HOME"))
1439
+	return &DockerCli{addr, port, authConfig}
1439 1440
 }
1440 1441
 
1441 1442
 type DockerCli struct {
1442
-	host string
1443
-	port int
1443
+	host       string
1444
+	port       int
1445
+	authConfig *auth.AuthConfig
1444 1446
 }
... ...
@@ -466,10 +466,7 @@ type Registry struct {
466 466
 	authConfig *auth.AuthConfig
467 467
 }
468 468
 
469
-func NewRegistry(root string) *Registry {
470
-	// If the auth file does not exist, keep going
471
-	authConfig, _ := auth.LoadConfig(root)
472
-
469
+func NewRegistry(root string, authConfig *auth.AuthConfig) *Registry {
473 470
 	r := &Registry{
474 471
 		authConfig: authConfig,
475 472
 		client:     &http.Client{},
... ...
@@ -65,7 +65,7 @@ func init() {
65 65
 		runtime: runtime,
66 66
 	}
67 67
 	// Retrieve the Image
68
-	if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, false); err != nil {
68
+	if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, false, nil); err != nil {
69 69
 		panic(err)
70 70
 	}
71 71
 }
... ...
@@ -50,7 +50,7 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
50 50
 
51 51
 func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) {
52 52
 
53
-	results, err := registry.NewRegistry(srv.runtime.root).SearchRepositories(term)
53
+	results, err := registry.NewRegistry(srv.runtime.root, nil).SearchRepositories(term)
54 54
 	if err != nil {
55 55
 		return nil, err
56 56
 	}
... ...
@@ -394,8 +394,8 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, a
394 394
 	return nil
395 395
 }
396 396
 
397
-func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, json bool) error {
398
-	r := registry.NewRegistry(srv.runtime.root)
397
+func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, json bool, authConfig *auth.AuthConfig) error {
398
+	r := registry.NewRegistry(srv.runtime.root, authConfig)
399 399
 	out = utils.NewWriteFlusher(out)
400 400
 	if endpoint != "" {
401 401
 		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,
576 576
 	return nil
577 577
 }
578 578
 
579
-func (srv *Server) ImagePush(name, endpoint string, out io.Writer) error {
579
+func (srv *Server) ImagePush(name, endpoint string, out io.Writer, authConfig *auth.AuthConfig) error {
580 580
 	out = utils.NewWriteFlusher(out)
581 581
 	img, err := srv.runtime.graph.Get(name)
582
-	r := registry.NewRegistry(srv.runtime.root)
582
+	r := registry.NewRegistry(srv.runtime.root, authConfig)
583 583
 
584 584
 	if err != nil {
585 585
 		fmt.Fprintf(out, "The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name]))