Browse code

cliconfig: credentials: support getting all auths

docker build is broken because it sends to the daemon the full
cliconfig file which has only Email(s). This patch retrieves all auth
configs from the credentials store.

Signed-off-by: Antonio Murdaca <runcom@redhat.com>

Antonio Murdaca authored on 2016/03/02 02:04:35
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)
... ...
@@ -147,6 +147,11 @@ func getCredentials(c *cliconfig.ConfigFile, serverAddress string) (types.AuthCo
147 147
 	return s.Get(serverAddress)
148 148
 }
149 149
 
150
+func getAllCredentials(c *cliconfig.ConfigFile) (map[string]types.AuthConfig, error) {
151
+	s := loadCredentialsStore(c)
152
+	return s.GetAll()
153
+}
154
+
150 155
 // storeCredentials saves the user credentials in a credentials store.
151 156
 // The store is determined by the config file settings.
152 157
 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))