diff --git a/docker/docker_client.go b/docker/docker_client.go index ae986de42d..481fa43dc8 100644 --- a/docker/docker_client.go +++ b/docker/docker_client.go @@ -52,7 +52,7 @@ func newDockerClient(ctx *types.SystemContext, ref dockerReference, write bool) if registry == dockerHostname { registry = dockerRegistry } - username, password, err := getAuth(ref.ref.Hostname()) + username, password, err := getAuth(ctx, ref.ref.Hostname()) if err != nil { return nil, err } @@ -243,7 +243,10 @@ func (c *dockerClient) getBearerToken(realm, service, scope string) (string, err return tokenStruct.Token, nil } -func getAuth(registry string) (string, string, error) { +func getAuth(ctx *types.SystemContext, registry string) (string, string, error) { + if ctx != nil && ctx.DockerAuthConfig != nil { + return ctx.DockerAuthConfig.Username, ctx.DockerAuthConfig.Password, nil + } // TODO(runcom): get this from *cli.Context somehow //if username != "" && password != "" { //return username, password, nil diff --git a/docker/docker_client_test.go b/docker/docker_client_test.go index 17de920d47..dc1425df8b 100644 --- a/docker/docker_client_test.go +++ b/docker/docker_client_test.go @@ -10,6 +10,7 @@ import ( "reflect" "testing" + "github.com/containers/image/types" "github.com/docker/docker/pkg/homedir" ) @@ -43,6 +44,7 @@ func TestGetAuth(t *testing.T) { expectedUsername string expectedPassword string expectedError error + ctx *types.SystemContext }{ { name: "empty hostname", @@ -130,6 +132,21 @@ func TestGetAuth(t *testing.T) { expectedUsername: "me", expectedPassword: "mine", }, + { + name: "use system context", + hostname: "example.org", + authConfig: makeTestAuthConfig(testAuthConfigDataMap{ + "example.org": testAuthConfigData{"user", "pw"}, + }), + expectedUsername: "foo", + expectedPassword: "bar", + ctx: &types.SystemContext{ + DockerAuthConfig: &types.DockerAuthConfig{ + Username: "foo", + Password: "bar", + }, + }, + }, } { contents, err := json.MarshalIndent(&tc.authConfig, "", " ") if err != nil { @@ -141,7 +158,11 @@ func TestGetAuth(t *testing.T) { continue } - username, password, err := getAuth(tc.hostname) + var ctx *types.SystemContext + if tc.ctx != nil { + ctx = tc.ctx + } + username, password, err := getAuth(ctx, tc.hostname) if err == nil && tc.expectedError != nil { t.Errorf("[%s] got unexpected non error and username=%q, password=%q", tc.name, username, password) continue @@ -222,7 +243,7 @@ func TestGetAuthFromLegacyFile(t *testing.T) { continue } - username, password, err := getAuth(tc.hostname) + username, password, err := getAuth(nil, tc.hostname) if err == nil && tc.expectedError != nil { t.Errorf("[%s] got unexpected non error and username=%q, password=%q", tc.name, username, password) continue @@ -293,7 +314,7 @@ func TestGetAuthPreferNewConfig(t *testing.T) { } } - username, password, err := getAuth("index.docker.io") + username, password, err := getAuth(nil, "index.docker.io") if err != nil { t.Fatalf("got unexpected error: %#+v", err) } @@ -330,7 +351,7 @@ func TestGetAuthFailsOnBadInput(t *testing.T) { configPath := filepath.Join(configDir, "config.json") // no config file present - username, password, err := getAuth("index.docker.io") + username, password, err := getAuth(nil, "index.docker.io") if err != nil { t.Fatalf("got unexpected error: %#+v", err) } @@ -341,7 +362,7 @@ func TestGetAuthFailsOnBadInput(t *testing.T) { if err := ioutil.WriteFile(configPath, []byte("Json rocks! Unless it doesn't."), 0640); err != nil { t.Fatalf("failed to write file %q: %v", configPath, err) } - username, password, err = getAuth("index.docker.io") + username, password, err = getAuth(nil, "index.docker.io") if err == nil { t.Fatalf("got unexpected non-error: username=%q, password=%q", username, password) } @@ -352,7 +373,7 @@ func TestGetAuthFailsOnBadInput(t *testing.T) { // remove the invalid config file os.RemoveAll(configPath) // no config file present - username, password, err = getAuth("index.docker.io") + username, password, err = getAuth(nil, "index.docker.io") if err != nil { t.Fatalf("got unexpected error: %#+v", err) } @@ -364,7 +385,7 @@ func TestGetAuthFailsOnBadInput(t *testing.T) { if err := ioutil.WriteFile(configPath, []byte("I'm certainly not a json string."), 0640); err != nil { t.Fatalf("failed to write file %q: %v", configPath, err) } - username, password, err = getAuth("index.docker.io") + username, password, err = getAuth(nil, "index.docker.io") if err == nil { t.Fatalf("got unexpected non-error: username=%q, password=%q", username, password) } diff --git a/types/types.go b/types/types.go index c4a15b3b4c..ab185a6f9e 100644 --- a/types/types.go +++ b/types/types.go @@ -205,6 +205,12 @@ type ImageInspectInfo struct { Layers []string } +// DockerAuthConfig contains authorization information for connecting to a registry. +type DockerAuthConfig struct { + Username string + Password string +} + // SystemContext allows parametrizing access to implicitly-accessed resources, // like configuration files in /etc and users' login state in their home directory. // Various components can share the same field only if their semantics is exactly @@ -228,4 +234,6 @@ type SystemContext struct { // === docker.Transport overrides === DockerCertPath string // If not "", a directory containing "cert.pem" and "key.pem" used when talking to a Docker Registry DockerInsecureSkipTLSVerify bool // Allow contacting docker registries over HTTP, or HTTPS with failed TLS verification. Note that this does not affect other TLS connections. + // if nil, the library tries to parse ~/.docker/config.json to retrieve credentials + DockerAuthConfig *DockerAuthConfig }