Просмотр исходного кода

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

cliconfig: credentials: support getting all auths
David Calavera 9 лет назад
Родитель
Сommit
f4cb5f4a32

+ 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

@@ -141,6 +141,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))