Browse code

Merge pull request #20824 from runcom/fix-creds-store

cliconfig: credentials: support getting all auths

David Calavera authored on 2016/03/03 09:37:57
Showing 11 changed files
... ...
@@ -229,7 +229,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
229 229
 		ShmSize:        shmSize,
230 230
 		Ulimits:        flUlimits.GetList(),
231 231
 		BuildArgs:      runconfigopts.ConvertKVStringsToMap(flBuildArg.GetAll()),
232
-		AuthConfigs:    cli.configFile.AuthConfigs,
232
+		AuthConfigs:    cli.retrieveAuthConfigs(),
233 233
 	}
234 234
 
235 235
 	response, err := cli.client.ImageBuild(context.Background(), options)
... ...
@@ -141,6 +141,11 @@ func getCredentials(c *cliconfig.ConfigFile, serverAddress string) (types.AuthCo
141 141
 	return s.Get(serverAddress)
142 142
 }
143 143
 
144
+func getAllCredentials(c *cliconfig.ConfigFile) (map[string]types.AuthConfig, error) {
145
+	s := loadCredentialsStore(c)
146
+	return s.GetAll()
147
+}
148
+
144 149
 // storeCredentials saves the user credentials in a credentials store.
145 150
 // The store is determined by the config file settings.
146 151
 func storeCredentials(c *cliconfig.ConfigFile, auth types.AuthConfig) error {
... ...
@@ -193,3 +193,8 @@ func (cli *DockerCli) resolveAuthConfig(index *registrytypes.IndexInfo) types.Au
193 193
 	a, _ := getCredentials(cli.configFile, configKey)
194 194
 	return a
195 195
 }
196
+
197
+func (cli *DockerCli) retrieveAuthConfigs() map[string]types.AuthConfig {
198
+	acs, _ := getAllCredentials(cli.configFile)
199
+	return acs
200
+}
... ...
@@ -10,6 +10,8 @@ type Store interface {
10 10
 	Erase(serverAddress string) error
11 11
 	// Get retrieves credentials from the store for a given server.
12 12
 	Get(serverAddress string) (types.AuthConfig, error)
13
+	// GetAll retrieves all the credentials from the store.
14
+	GetAll() (map[string]types.AuthConfig, error)
13 15
 	// Store saves credentials in the store.
14 16
 	Store(authConfig types.AuthConfig) error
15 17
 }
... ...
@@ -43,6 +43,10 @@ func (c *fileStore) Get(serverAddress string) (types.AuthConfig, error) {
43 43
 	return authConfig, nil
44 44
 }
45 45
 
46
+func (c *fileStore) GetAll() (map[string]types.AuthConfig, error) {
47
+	return c.file.AuthConfigs, nil
48
+}
49
+
46 50
 // Store saves the given credentials in the file store.
47 51
 func (c *fileStore) Store(authConfig types.AuthConfig) error {
48 52
 	c.file.AuthConfigs[authConfig.ServerAddress] = authConfig
... ...
@@ -70,6 +70,44 @@ func TestFileStoreGet(t *testing.T) {
70 70
 	}
71 71
 }
72 72
 
73
+func TestFileStoreGetAll(t *testing.T) {
74
+	s1 := "https://example.com"
75
+	s2 := "https://example2.com"
76
+	f := newConfigFile(map[string]types.AuthConfig{
77
+		s1: {
78
+			Auth:          "super_secret_token",
79
+			Email:         "foo@example.com",
80
+			ServerAddress: "https://example.com",
81
+		},
82
+		s2: {
83
+			Auth:          "super_secret_token2",
84
+			Email:         "foo@example2.com",
85
+			ServerAddress: "https://example2.com",
86
+		},
87
+	})
88
+
89
+	s := NewFileStore(f)
90
+	as, err := s.GetAll()
91
+	if err != nil {
92
+		t.Fatal(err)
93
+	}
94
+	if len(as) != 2 {
95
+		t.Fatalf("wanted 2, got %d", len(as))
96
+	}
97
+	if as[s1].Auth != "super_secret_token" {
98
+		t.Fatalf("expected auth `super_secret_token`, got %s", as[s1].Auth)
99
+	}
100
+	if as[s1].Email != "foo@example.com" {
101
+		t.Fatalf("expected email `foo@example.com`, got %s", as[s1].Email)
102
+	}
103
+	if as[s2].Auth != "super_secret_token2" {
104
+		t.Fatalf("expected auth `super_secret_token2`, got %s", as[s2].Auth)
105
+	}
106
+	if as[s2].Email != "foo@example2.com" {
107
+		t.Fatalf("expected email `foo@example2.com`, got %s", as[s2].Email)
108
+	}
109
+}
110
+
73 111
 func TestFileStoreErase(t *testing.T) {
74 112
 	f := newConfigFile(map[string]types.AuthConfig{
75 113
 		"https://example.com": {
... ...
@@ -81,6 +81,20 @@ func (c *nativeStore) Get(serverAddress string) (types.AuthConfig, error) {
81 81
 	return auth, nil
82 82
 }
83 83
 
84
+// GetAll retrieves all the credentials from the native store.
85
+func (c *nativeStore) GetAll() (map[string]types.AuthConfig, error) {
86
+	auths, _ := c.fileStore.GetAll()
87
+
88
+	for s, ac := range auths {
89
+		creds, _ := c.getCredentialsFromStore(s)
90
+		ac.Username = creds.Username
91
+		ac.Password = creds.Password
92
+		auths[s] = ac
93
+	}
94
+
95
+	return auths, nil
96
+}
97
+
84 98
 // Store saves the given credentials in the file store.
85 99
 func (c *nativeStore) Store(authConfig types.AuthConfig) error {
86 100
 	if err := c.storeCredentialsInStore(authConfig); err != nil {
... ...
@@ -135,7 +149,7 @@ func (c *nativeStore) getCredentialsFromStore(serverAddress string) (types.AuthC
135 135
 			return ret, nil
136 136
 		}
137 137
 
138
-		logrus.Debugf("error adding credentials - err: %v, out: `%s`", err, t)
138
+		logrus.Debugf("error getting credentials - err: %v, out: `%s`", err, t)
139 139
 		return ret, fmt.Errorf(t)
140 140
 	}
141 141
 
... ...
@@ -158,7 +172,7 @@ func (c *nativeStore) eraseCredentialsFromStore(serverURL string) error {
158 158
 	out, err := cmd.Output()
159 159
 	if err != nil {
160 160
 		t := strings.TrimSpace(string(out))
161
-		logrus.Debugf("error adding credentials - err: %v, out: `%s`", err, t)
161
+		logrus.Debugf("error erasing credentials - err: %v, out: `%s`", err, t)
162 162
 		return fmt.Errorf(t)
163 163
 	}
164 164
 
... ...
@@ -13,6 +13,7 @@ import (
13 13
 
14 14
 const (
15 15
 	validServerAddress   = "https://index.docker.io/v1"
16
+	validServerAddress2  = "https://example.com:5002"
16 17
 	invalidServerAddress = "https://foobar.example.com"
17 18
 	missingCredsAddress  = "https://missing.docker.io/v1"
18 19
 )
... ...
@@ -46,7 +47,7 @@ func (m *mockCommand) Output() ([]byte, error) {
46 46
 		}
47 47
 	case "get":
48 48
 		switch inS {
49
-		case validServerAddress:
49
+		case validServerAddress, validServerAddress2:
50 50
 			return []byte(`{"Username": "foo", "Password": "bar"}`), nil
51 51
 		case missingCredsAddress:
52 52
 			return []byte(errCredentialsNotFound.Error()), errCommandExited
... ...
@@ -67,7 +68,7 @@ func (m *mockCommand) Output() ([]byte, error) {
67 67
 		}
68 68
 	}
69 69
 
70
-	return []byte("unknown argument"), errCommandExited
70
+	return []byte(fmt.Sprintf("unknown argument %q with %q", m.arg, inS)), errCommandExited
71 71
 }
72 72
 
73 73
 // Input sets the input to send to a remote credentials helper.
... ...
@@ -178,6 +179,50 @@ func TestNativeStoreGet(t *testing.T) {
178 178
 	}
179 179
 }
180 180
 
181
+func TestNativeStoreGetAll(t *testing.T) {
182
+	f := newConfigFile(map[string]types.AuthConfig{
183
+		validServerAddress: {
184
+			Email: "foo@example.com",
185
+		},
186
+		validServerAddress2: {
187
+			Email: "foo@example2.com",
188
+		},
189
+	})
190
+	f.CredentialsStore = "mock"
191
+
192
+	s := &nativeStore{
193
+		commandFn: mockCommandFn,
194
+		fileStore: NewFileStore(f),
195
+	}
196
+	as, err := s.GetAll()
197
+	if err != nil {
198
+		t.Fatal(err)
199
+	}
200
+
201
+	if len(as) != 2 {
202
+		t.Fatalf("wanted 2, got %d", len(as))
203
+	}
204
+
205
+	if as[validServerAddress].Username != "foo" {
206
+		t.Fatalf("expected username `foo` for %s, got %s", validServerAddress, as[validServerAddress].Username)
207
+	}
208
+	if as[validServerAddress].Password != "bar" {
209
+		t.Fatalf("expected password `bar` for %s, got %s", validServerAddress, as[validServerAddress].Password)
210
+	}
211
+	if as[validServerAddress].Email != "foo@example.com" {
212
+		t.Fatalf("expected email `foo@example.com` for %s, got %s", validServerAddress, as[validServerAddress].Email)
213
+	}
214
+	if as[validServerAddress2].Username != "foo" {
215
+		t.Fatalf("expected username `foo` for %s, got %s", validServerAddress2, as[validServerAddress2].Username)
216
+	}
217
+	if as[validServerAddress2].Password != "bar" {
218
+		t.Fatalf("expected password `bar` for %s, got %s", validServerAddress2, as[validServerAddress2].Password)
219
+	}
220
+	if as[validServerAddress2].Email != "foo@example2.com" {
221
+		t.Fatalf("expected email `foo@example2.com` for %s, got %s", validServerAddress2, as[validServerAddress2].Email)
222
+	}
223
+}
224
+
181 225
 func TestNativeStoreGetMissingCredentials(t *testing.T) {
182 226
 	f := newConfigFile(map[string]types.AuthConfig{
183 227
 		validServerAddress: {
... ...
@@ -6589,3 +6589,45 @@ func (s *DockerRegistryAuthSuite) TestBuildFromAuthenticatedRegistry(c *check.C)
6589 6589
 
6590 6590
 	c.Assert(err, checker.IsNil)
6591 6591
 }
6592
+
6593
+func (s *DockerRegistryAuthSuite) TestBuildWithExternalAuth(c *check.C) {
6594
+	osPath := os.Getenv("PATH")
6595
+	defer os.Setenv("PATH", osPath)
6596
+
6597
+	workingDir, err := os.Getwd()
6598
+	c.Assert(err, checker.IsNil)
6599
+	absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
6600
+	c.Assert(err, checker.IsNil)
6601
+	testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
6602
+
6603
+	os.Setenv("PATH", testPath)
6604
+
6605
+	repoName := fmt.Sprintf("%v/dockercli/busybox:authtest", privateRegistryURL)
6606
+
6607
+	tmp, err := ioutil.TempDir("", "integration-cli-")
6608
+	c.Assert(err, checker.IsNil)
6609
+
6610
+	externalAuthConfig := `{ "credsStore": "shell-test" }`
6611
+
6612
+	configPath := filepath.Join(tmp, "config.json")
6613
+	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
6614
+	c.Assert(err, checker.IsNil)
6615
+
6616
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
6617
+
6618
+	b, err := ioutil.ReadFile(configPath)
6619
+	c.Assert(err, checker.IsNil)
6620
+	c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
6621
+
6622
+	dockerCmd(c, "--config", tmp, "tag", "busybox", repoName)
6623
+	dockerCmd(c, "--config", tmp, "push", repoName)
6624
+
6625
+	// make sure the image is pulled when building
6626
+	dockerCmd(c, "rmi", repoName)
6627
+
6628
+	buildCmd := exec.Command(dockerBinary, "--config", tmp, "build", "-")
6629
+	buildCmd.Stdin = strings.NewReader(fmt.Sprintf("FROM %s", repoName))
6630
+
6631
+	out, _, err := runCommandWithOutput(buildCmd)
6632
+	c.Assert(err, check.IsNil, check.Commentf(out))
6633
+}
... ...
@@ -385,7 +385,7 @@ func (s *DockerRegistryAuthSuite) TestPullWithExternalAuth(c *check.C) {
385 385
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
386 386
 	c.Assert(err, checker.IsNil)
387 387
 
388
-	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, "-e", s.reg.email, privateRegistryURL)
388
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
389 389
 
390 390
 	b, err := ioutil.ReadFile(configPath)
391 391
 	c.Assert(err, checker.IsNil)
... ...
@@ -38,7 +38,6 @@ import (
38 38
 func init() {
39 39
 	cmd := exec.Command(dockerBinary, "images")
40 40
 	cmd.Env = appendBaseEnv(true)
41
-	fmt.Println("foobar", cmd.Env)
42 41
 	out, err := cmd.CombinedOutput()
43 42
 	if err != nil {
44 43
 		panic(fmt.Errorf("err=%v\nout=%s\n", err, out))