diff --git a/integration-cli/check_test.go b/integration-cli/check_test.go index cac8176074..8e2f1806f1 100644 --- a/integration-cli/check_test.go +++ b/integration-cli/check_test.go @@ -49,7 +49,7 @@ type DockerRegistrySuite struct { func (s *DockerRegistrySuite) SetUpTest(c *check.C) { testRequires(c, DaemonIsLinux) - s.reg = setupRegistry(c, false) + s.reg = setupRegistry(c, false, false) s.d = NewDaemon(c) } @@ -77,7 +77,7 @@ type DockerSchema1RegistrySuite struct { func (s *DockerSchema1RegistrySuite) SetUpTest(c *check.C) { testRequires(c, DaemonIsLinux) - s.reg = setupRegistry(c, true) + s.reg = setupRegistry(c, true, false) s.d = NewDaemon(c) } @@ -91,6 +91,36 @@ func (s *DockerSchema1RegistrySuite) TearDownTest(c *check.C) { s.ds.TearDownTest(c) } +func init() { + check.Suite(&DockerRegistryAuthSuite{ + ds: &DockerSuite{}, + }) +} + +type DockerRegistryAuthSuite struct { + ds *DockerSuite + reg *testRegistryV2 + d *Daemon +} + +func (s *DockerRegistryAuthSuite) SetUpTest(c *check.C) { + testRequires(c, DaemonIsLinux) + s.reg = setupRegistry(c, false, true) + s.d = NewDaemon(c) +} + +func (s *DockerRegistryAuthSuite) TearDownTest(c *check.C) { + if s.reg != nil { + out, err := s.d.Cmd("logout", privateRegistryURL) + c.Assert(err, check.IsNil, check.Commentf(out)) + s.reg.Close() + } + if s.d != nil { + s.d.Stop() + } + s.ds.TearDownTest(c) +} + func init() { check.Suite(&DockerDaemonSuite{ ds: &DockerSuite{}, @@ -128,7 +158,7 @@ type DockerTrustSuite struct { } func (s *DockerTrustSuite) SetUpTest(c *check.C) { - s.reg = setupRegistry(c, false) + s.reg = setupRegistry(c, false, false) s.not = setupNotary(c) } diff --git a/integration-cli/docker_cli_login_test.go b/integration-cli/docker_cli_login_test.go index 13d43404a1..ab6294092d 100644 --- a/integration-cli/docker_cli_login_test.go +++ b/integration-cli/docker_cli_login_test.go @@ -17,5 +17,14 @@ func (s *DockerSuite) TestLoginWithoutTTY(c *check.C) { // run the command and block until it's done err := cmd.Run() c.Assert(err, checker.NotNil) //"Expected non nil err when loginning in & TTY not available" - +} + +func (s *DockerRegistryAuthSuite) TestLoginToPrivateRegistry(c *check.C) { + // wrong credentials + out, _, err := dockerCmdWithError("login", "-u", s.reg.username, "-p", "WRONGPASSWORD", "-e", s.reg.email, privateRegistryURL) + c.Assert(err, checker.NotNil, check.Commentf(out)) + c.Assert(out, checker.Contains, "401 Unauthorized") + + // now it's fine + dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, "-e", s.reg.email, privateRegistryURL) } diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go index b6177c5831..d23c6e3a19 100644 --- a/integration-cli/docker_utils.go +++ b/integration-cli/docker_utils.go @@ -1554,9 +1554,9 @@ func daemonTime(c *check.C) time.Time { return dt } -func setupRegistry(c *check.C, schema1 bool) *testRegistryV2 { +func setupRegistry(c *check.C, schema1, auth bool) *testRegistryV2 { testRequires(c, RegistryHosting) - reg, err := newTestRegistryV2(c, schema1) + reg, err := newTestRegistryV2(c, schema1, auth) c.Assert(err, check.IsNil) // Wait for registry to be ready to serve requests. diff --git a/integration-cli/registry.go b/integration-cli/registry.go index d4038d24b6..28fc054ed1 100644 --- a/integration-cli/registry.go +++ b/integration-cli/registry.go @@ -18,28 +18,55 @@ const ( ) type testRegistryV2 struct { - cmd *exec.Cmd - dir string + cmd *exec.Cmd + dir string + username string + password string + email string } -func newTestRegistryV2(c *check.C, schema1 bool) (*testRegistryV2, error) { +func newTestRegistryV2(c *check.C, schema1, auth bool) (*testRegistryV2, error) { + tmp, err := ioutil.TempDir("", "registry-test-") + if err != nil { + return nil, err + } template := `version: 0.1 loglevel: debug storage: filesystem: rootdirectory: %s http: - addr: %s` - tmp, err := ioutil.TempDir("", "registry-test-") - if err != nil { - return nil, err + addr: %s +%s` + var ( + htpasswd string + username string + password string + email string + ) + if auth { + htpasswdPath := filepath.Join(tmp, "htpasswd") + // generated with: htpasswd -Bbn testuser testpassword + userpasswd := "testuser:$2y$05$sBsSqk0OpSD1uTZkHXc4FeJ0Z70wLQdAX/82UiHuQOKbNbBrzs63m" + username = "testuser" + password = "testpassword" + email = "test@test.org" + if err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)); err != nil { + return nil, err + } + htpasswd = fmt.Sprintf(`auth: + htpasswd: + realm: basic-realm + path: %s +`, htpasswdPath) } + confPath := filepath.Join(tmp, "config.yaml") config, err := os.Create(confPath) if err != nil { return nil, err } - if _, err := fmt.Fprintf(config, template, tmp, privateRegistryURL); err != nil { + if _, err := fmt.Fprintf(config, template, tmp, privateRegistryURL, htpasswd); err != nil { os.RemoveAll(tmp) return nil, err } @@ -57,8 +84,11 @@ http: return nil, err } return &testRegistryV2{ - cmd: cmd, - dir: tmp, + cmd: cmd, + dir: tmp, + username: username, + password: password, + email: email, }, nil } @@ -68,7 +98,14 @@ func (t *testRegistryV2) Ping() error { if err != nil { return err } - if resp.StatusCode != http.StatusOK { + resp.Body.Close() + + fail := resp.StatusCode != http.StatusOK + if t.username != "" { + // unauthorized is a _good_ status when pinging v2/ and it needs auth + fail = fail && resp.StatusCode != http.StatusUnauthorized + } + if fail { return fmt.Errorf("registry ping replied with an unexpected status code %d", resp.StatusCode) } return nil