Browse Source

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 years ago
parent
commit
44152144ca

+ 1 - 1
api/client/build.go

@@ -229,7 +229,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 		ShmSize:        shmSize,
 		ShmSize:        shmSize,
 		Ulimits:        flUlimits.GetList(),
 		Ulimits:        flUlimits.GetList(),
 		BuildArgs:      runconfigopts.ConvertKVStringsToMap(flBuildArg.GetAll()),
 		BuildArgs:      runconfigopts.ConvertKVStringsToMap(flBuildArg.GetAll()),
-		AuthConfigs:    cli.configFile.AuthConfigs,
+		AuthConfigs:    cli.retrieveAuthConfigs(),
 	}
 	}
 
 
 	response, err := cli.client.ImageBuild(context.Background(), options)
 	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)
 	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.
 // storeCredentials saves the user credentials in a credentials store.
 // The store is determined by the config file settings.
 // The store is determined by the config file settings.
 func storeCredentials(c *cliconfig.ConfigFile, auth types.AuthConfig) error {
 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)
 	a, _ := getCredentials(cli.configFile, configKey)
 	return a
 	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
 	Erase(serverAddress string) error
 	// Get retrieves credentials from the store for a given server.
 	// Get retrieves credentials from the store for a given server.
 	Get(serverAddress string) (types.AuthConfig, error)
 	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 saves credentials in the store.
 	Store(authConfig types.AuthConfig) error
 	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
 	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.
 // Store saves the given credentials in the file store.
 func (c *fileStore) Store(authConfig types.AuthConfig) error {
 func (c *fileStore) Store(authConfig types.AuthConfig) error {
 	c.file.AuthConfigs[authConfig.ServerAddress] = authConfig
 	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) {
 func TestFileStoreErase(t *testing.T) {
 	f := newConfigFile(map[string]types.AuthConfig{
 	f := newConfigFile(map[string]types.AuthConfig{
 		"https://example.com": {
 		"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
 	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.
 // Store saves the given credentials in the file store.
 func (c *nativeStore) Store(authConfig types.AuthConfig) error {
 func (c *nativeStore) Store(authConfig types.AuthConfig) error {
 	if err := c.storeCredentialsInStore(authConfig); err != nil {
 	if err := c.storeCredentialsInStore(authConfig); err != nil {
@@ -135,7 +149,7 @@ func (c *nativeStore) getCredentialsFromStore(serverAddress string) (types.AuthC
 			return ret, nil
 			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)
 		return ret, fmt.Errorf(t)
 	}
 	}
 
 
@@ -158,7 +172,7 @@ func (c *nativeStore) eraseCredentialsFromStore(serverURL string) error {
 	out, err := cmd.Output()
 	out, err := cmd.Output()
 	if err != nil {
 	if err != nil {
 		t := strings.TrimSpace(string(out))
 		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)
 		return fmt.Errorf(t)
 	}
 	}
 
 

+ 47 - 2
cliconfig/credentials/native_store_test.go

@@ -13,6 +13,7 @@ import (
 
 
 const (
 const (
 	validServerAddress   = "https://index.docker.io/v1"
 	validServerAddress   = "https://index.docker.io/v1"
+	validServerAddress2  = "https://example.com:5002"
 	invalidServerAddress = "https://foobar.example.com"
 	invalidServerAddress = "https://foobar.example.com"
 	missingCredsAddress  = "https://missing.docker.io/v1"
 	missingCredsAddress  = "https://missing.docker.io/v1"
 )
 )
@@ -46,7 +47,7 @@ func (m *mockCommand) Output() ([]byte, error) {
 		}
 		}
 	case "get":
 	case "get":
 		switch inS {
 		switch inS {
-		case validServerAddress:
+		case validServerAddress, validServerAddress2:
 			return []byte(`{"Username": "foo", "Password": "bar"}`), nil
 			return []byte(`{"Username": "foo", "Password": "bar"}`), nil
 		case missingCredsAddress:
 		case missingCredsAddress:
 			return []byte(errCredentialsNotFound.Error()), errCommandExited
 			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.
 // 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) {
 func TestNativeStoreGetMissingCredentials(t *testing.T) {
 	f := newConfigFile(map[string]types.AuthConfig{
 	f := newConfigFile(map[string]types.AuthConfig{
 		validServerAddress: {
 		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)
 	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)
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 	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)
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)
 	c.Assert(err, checker.IsNil)

+ 0 - 1
integration-cli/docker_utils.go

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