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

cliconfig: credentials: support getting all auths
This commit is contained in:
David Calavera 2016-03-02 16:37:57 -08:00
commit f4cb5f4a32
11 changed files with 161 additions and 7 deletions

View file

@ -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)

View file

@ -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 {

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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": {

View file

@ -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)
}

View file

@ -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: {

View file

@ -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))
}

View file

@ -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)

View file

@ -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))