浏览代码

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 9 年之前
父节点
当前提交
44152144ca

+ 1 - 1
api/client/build.go

@@ -229,7 +229,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 		ShmSize:        shmSize,
 		Ulimits:        flUlimits.GetList(),
 		BuildArgs:      runconfigopts.ConvertKVStringsToMap(flBuildArg.GetAll()),
-		AuthConfigs:    cli.configFile.AuthConfigs,
+		AuthConfigs:    cli.retrieveAuthConfigs(),
 	}
 
 	response, err := cli.client.ImageBuild(context.Background(), options)

+ 5 - 0
api/client/login.go

@@ -147,6 +147,11 @@ func getCredentials(c *cliconfig.ConfigFile, serverAddress string) (types.AuthCo
 	return s.Get(serverAddress)
 }
 
+func getAllCredentials(c *cliconfig.ConfigFile) (map[string]types.AuthConfig, error) {
+	s := loadCredentialsStore(c)
+	return s.GetAll()
+}
+
 // storeCredentials saves the user credentials in a credentials store.
 // The store is determined by the config file settings.
 func storeCredentials(c *cliconfig.ConfigFile, auth types.AuthConfig) error {

+ 5 - 0
api/client/utils.go

@@ -193,3 +193,8 @@ func (cli *DockerCli) resolveAuthConfig(index *registrytypes.IndexInfo) types.Au
 	a, _ := getCredentials(cli.configFile, configKey)
 	return a
 }
+
+func (cli *DockerCli) retrieveAuthConfigs() map[string]types.AuthConfig {
+	acs, _ := getAllCredentials(cli.configFile)
+	return acs
+}

+ 2 - 0
cliconfig/credentials/credentials.go

@@ -10,6 +10,8 @@ type Store interface {
 	Erase(serverAddress string) error
 	// Get retrieves credentials from the store for a given server.
 	Get(serverAddress string) (types.AuthConfig, error)
+	// GetAll retrieves all the credentials from the store.
+	GetAll() (map[string]types.AuthConfig, error)
 	// Store saves credentials in the store.
 	Store(authConfig types.AuthConfig) error
 }

+ 4 - 0
cliconfig/credentials/file_store.go

@@ -43,6 +43,10 @@ func (c *fileStore) Get(serverAddress string) (types.AuthConfig, error) {
 	return authConfig, nil
 }
 
+func (c *fileStore) GetAll() (map[string]types.AuthConfig, error) {
+	return c.file.AuthConfigs, nil
+}
+
 // Store saves the given credentials in the file store.
 func (c *fileStore) Store(authConfig types.AuthConfig) error {
 	c.file.AuthConfigs[authConfig.ServerAddress] = authConfig

+ 38 - 0
cliconfig/credentials/file_store_test.go

@@ -70,6 +70,44 @@ func TestFileStoreGet(t *testing.T) {
 	}
 }
 
+func TestFileStoreGetAll(t *testing.T) {
+	s1 := "https://example.com"
+	s2 := "https://example2.com"
+	f := newConfigFile(map[string]types.AuthConfig{
+		s1: {
+			Auth:          "super_secret_token",
+			Email:         "foo@example.com",
+			ServerAddress: "https://example.com",
+		},
+		s2: {
+			Auth:          "super_secret_token2",
+			Email:         "foo@example2.com",
+			ServerAddress: "https://example2.com",
+		},
+	})
+
+	s := NewFileStore(f)
+	as, err := s.GetAll()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(as) != 2 {
+		t.Fatalf("wanted 2, got %d", len(as))
+	}
+	if as[s1].Auth != "super_secret_token" {
+		t.Fatalf("expected auth `super_secret_token`, got %s", as[s1].Auth)
+	}
+	if as[s1].Email != "foo@example.com" {
+		t.Fatalf("expected email `foo@example.com`, got %s", as[s1].Email)
+	}
+	if as[s2].Auth != "super_secret_token2" {
+		t.Fatalf("expected auth `super_secret_token2`, got %s", as[s2].Auth)
+	}
+	if as[s2].Email != "foo@example2.com" {
+		t.Fatalf("expected email `foo@example2.com`, got %s", as[s2].Email)
+	}
+}
+
 func TestFileStoreErase(t *testing.T) {
 	f := newConfigFile(map[string]types.AuthConfig{
 		"https://example.com": {

+ 16 - 2
cliconfig/credentials/native_store.go

@@ -81,6 +81,20 @@ func (c *nativeStore) Get(serverAddress string) (types.AuthConfig, error) {
 	return auth, nil
 }
 
+// GetAll retrieves all the credentials from the native store.
+func (c *nativeStore) GetAll() (map[string]types.AuthConfig, error) {
+	auths, _ := c.fileStore.GetAll()
+
+	for s, ac := range auths {
+		creds, _ := c.getCredentialsFromStore(s)
+		ac.Username = creds.Username
+		ac.Password = creds.Password
+		auths[s] = ac
+	}
+
+	return auths, nil
+}
+
 // Store saves the given credentials in the file store.
 func (c *nativeStore) Store(authConfig types.AuthConfig) error {
 	if err := c.storeCredentialsInStore(authConfig); err != nil {
@@ -135,7 +149,7 @@ func (c *nativeStore) getCredentialsFromStore(serverAddress string) (types.AuthC
 			return ret, nil
 		}
 
-		logrus.Debugf("error adding credentials - err: %v, out: `%s`", err, t)
+		logrus.Debugf("error getting credentials - err: %v, out: `%s`", err, t)
 		return ret, fmt.Errorf(t)
 	}
 
@@ -158,7 +172,7 @@ func (c *nativeStore) eraseCredentialsFromStore(serverURL string) error {
 	out, err := cmd.Output()
 	if err != nil {
 		t := strings.TrimSpace(string(out))
-		logrus.Debugf("error adding credentials - err: %v, out: `%s`", err, t)
+		logrus.Debugf("error erasing credentials - err: %v, out: `%s`", err, t)
 		return fmt.Errorf(t)
 	}
 

+ 47 - 2
cliconfig/credentials/native_store_test.go

@@ -13,6 +13,7 @@ import (
 
 const (
 	validServerAddress   = "https://index.docker.io/v1"
+	validServerAddress2  = "https://example.com:5002"
 	invalidServerAddress = "https://foobar.example.com"
 	missingCredsAddress  = "https://missing.docker.io/v1"
 )
@@ -46,7 +47,7 @@ func (m *mockCommand) Output() ([]byte, error) {
 		}
 	case "get":
 		switch inS {
-		case validServerAddress:
+		case validServerAddress, validServerAddress2:
 			return []byte(`{"Username": "foo", "Password": "bar"}`), nil
 		case missingCredsAddress:
 			return []byte(errCredentialsNotFound.Error()), errCommandExited
@@ -67,7 +68,7 @@ func (m *mockCommand) Output() ([]byte, error) {
 		}
 	}
 
-	return []byte("unknown argument"), errCommandExited
+	return []byte(fmt.Sprintf("unknown argument %q with %q", m.arg, inS)), errCommandExited
 }
 
 // Input sets the input to send to a remote credentials helper.
@@ -178,6 +179,50 @@ func TestNativeStoreGet(t *testing.T) {
 	}
 }
 
+func TestNativeStoreGetAll(t *testing.T) {
+	f := newConfigFile(map[string]types.AuthConfig{
+		validServerAddress: {
+			Email: "foo@example.com",
+		},
+		validServerAddress2: {
+			Email: "foo@example2.com",
+		},
+	})
+	f.CredentialsStore = "mock"
+
+	s := &nativeStore{
+		commandFn: mockCommandFn,
+		fileStore: NewFileStore(f),
+	}
+	as, err := s.GetAll()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(as) != 2 {
+		t.Fatalf("wanted 2, got %d", len(as))
+	}
+
+	if as[validServerAddress].Username != "foo" {
+		t.Fatalf("expected username `foo` for %s, got %s", validServerAddress, as[validServerAddress].Username)
+	}
+	if as[validServerAddress].Password != "bar" {
+		t.Fatalf("expected password `bar` for %s, got %s", validServerAddress, as[validServerAddress].Password)
+	}
+	if as[validServerAddress].Email != "foo@example.com" {
+		t.Fatalf("expected email `foo@example.com` for %s, got %s", validServerAddress, as[validServerAddress].Email)
+	}
+	if as[validServerAddress2].Username != "foo" {
+		t.Fatalf("expected username `foo` for %s, got %s", validServerAddress2, as[validServerAddress2].Username)
+	}
+	if as[validServerAddress2].Password != "bar" {
+		t.Fatalf("expected password `bar` for %s, got %s", validServerAddress2, as[validServerAddress2].Password)
+	}
+	if as[validServerAddress2].Email != "foo@example2.com" {
+		t.Fatalf("expected email `foo@example2.com` for %s, got %s", validServerAddress2, as[validServerAddress2].Email)
+	}
+}
+
 func TestNativeStoreGetMissingCredentials(t *testing.T) {
 	f := newConfigFile(map[string]types.AuthConfig{
 		validServerAddress: {

+ 42 - 0
integration-cli/docker_cli_build_test.go

@@ -6589,3 +6589,45 @@ func (s *DockerRegistryAuthSuite) TestBuildFromAuthenticatedRegistry(c *check.C)
 
 	c.Assert(err, checker.IsNil)
 }
+
+func (s *DockerRegistryAuthSuite) TestBuildWithExternalAuth(c *check.C) {
+	osPath := os.Getenv("PATH")
+	defer os.Setenv("PATH", osPath)
+
+	workingDir, err := os.Getwd()
+	c.Assert(err, checker.IsNil)
+	absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
+	c.Assert(err, checker.IsNil)
+	testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
+
+	os.Setenv("PATH", testPath)
+
+	repoName := fmt.Sprintf("%v/dockercli/busybox:authtest", privateRegistryURL)
+
+	tmp, err := ioutil.TempDir("", "integration-cli-")
+	c.Assert(err, checker.IsNil)
+
+	externalAuthConfig := `{ "credsStore": "shell-test" }`
+
+	configPath := filepath.Join(tmp, "config.json")
+	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
+	c.Assert(err, checker.IsNil)
+
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
+
+	b, err := ioutil.ReadFile(configPath)
+	c.Assert(err, checker.IsNil)
+	c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
+
+	dockerCmd(c, "--config", tmp, "tag", "busybox", repoName)
+	dockerCmd(c, "--config", tmp, "push", repoName)
+
+	// make sure the image is pulled when building
+	dockerCmd(c, "rmi", repoName)
+
+	buildCmd := exec.Command(dockerBinary, "--config", tmp, "build", "-")
+	buildCmd.Stdin = strings.NewReader(fmt.Sprintf("FROM %s", repoName))
+
+	out, _, err := runCommandWithOutput(buildCmd)
+	c.Assert(err, check.IsNil, check.Commentf(out))
+}

+ 1 - 1
integration-cli/docker_cli_pull_local_test.go

@@ -385,7 +385,7 @@ func (s *DockerRegistryAuthSuite) TestPullWithExternalAuth(c *check.C) {
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 
-	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, "-e", s.reg.email, privateRegistryURL)
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
 
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)

+ 0 - 1
integration-cli/docker_utils.go

@@ -38,7 +38,6 @@ import (
 func init() {
 	cmd := exec.Command(dockerBinary, "images")
 	cmd.Env = appendBaseEnv(true)
-	fmt.Println("foobar", cmd.Env)
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		panic(fmt.Errorf("err=%v\nout=%s\n", err, out))