Skip to content

Commit

Permalink
Logout returns error if not logged in (#73)
Browse files Browse the repository at this point in the history
logout returns error if not logged in
  • Loading branch information
shizhMSFT committed Apr 17, 2019
1 parent 212c034 commit bc1ed35
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 3 deletions.
9 changes: 7 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pkg/auth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ package auth

import (
"context"
"errors"

"github.com/containerd/containerd/remotes"
)

// Common errors
var (
ErrNotLoggedIn = errors.New("not logged in")
)

// Client provides authentication operations for remotes.
type Client interface {
// Login logs in to a remote server identified by the hostname.
Expand Down
105 changes: 105 additions & 0 deletions pkg/auth/docker/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package docker

import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"

"github.com/docker/distribution/configuration"
"github.com/docker/distribution/registry"
_ "github.com/docker/distribution/registry/auth/htpasswd"
_ "github.com/docker/distribution/registry/storage/driver/inmemory"
"github.com/phayes/freeport"
"github.com/stretchr/testify/suite"
"golang.org/x/crypto/bcrypt"
)

var (
testConfig = "test.config"
testHtpasswd = "test.htpasswd"
testUsername = "alice"
testPassword = "wonderland"
)

type DockerClientTestSuite struct {
suite.Suite
DockerRegistryHost string
Client *Client
TempTestDir string
}

func newContext() context.Context {
return context.Background()
}

func (suite *DockerClientTestSuite) SetupSuite() {
tempDir, err := ioutil.TempDir("", "oras_auth_docker_test")
suite.Nil(err, "no error creating temp directory for test")
suite.TempTestDir = tempDir

// Create client
client, err := NewClient(filepath.Join(suite.TempTestDir, testConfig))
suite.Nil(err, "no error creating client")
var ok bool
suite.Client, ok = client.(*Client)
suite.True(ok, "NewClient returns a *docker.Client inside")

// Create htpasswd file with bcrypt
secret, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost)
suite.Nil(err, "no error generating bcrypt password for test htpasswd file")
authRecord := fmt.Sprintf("%s:%s\n", testUsername, string(secret))
htpasswdPath := filepath.Join(suite.TempTestDir, testHtpasswd)
err = ioutil.WriteFile(htpasswdPath, []byte(authRecord), 0644)
suite.Nil(err, "no error creating test htpasswd file")

// Registry config
config := &configuration.Configuration{}
port, err := freeport.GetFreePort()
suite.Nil(err, "no error finding free port for test registry")
suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port)
config.HTTP.Addr = fmt.Sprintf(":%d", port)
config.HTTP.DrainTimeout = time.Duration(10) * time.Second
config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
config.Auth = configuration.Auth{
"htpasswd": configuration.Parameters{
"realm": "localhost",
"path": htpasswdPath,
},
}
dockerRegistry, err := registry.NewRegistry(context.Background(), config)
suite.Nil(err, "no error finding free port for test registry")

// Start Docker registry
go dockerRegistry.ListenAndServe()
}

func (suite *DockerClientTestSuite) TearDownSuite() {
os.RemoveAll(suite.TempTestDir)
}

func (suite *DockerClientTestSuite) Test_0_Login() {
var err error

err = suite.Client.Login(newContext(), suite.DockerRegistryHost, "oscar", "opponent")
suite.NotNil(err, "error logging into registry with invalid credentials")

err = suite.Client.Login(newContext(), suite.DockerRegistryHost, testUsername, testPassword)
suite.Nil(err, "no error logging into registry with valid credentials")
}
func (suite *DockerClientTestSuite) Test_2_Logout() {
var err error

err = suite.Client.Logout(newContext(), "non-existing-host:42")
suite.NotNil(err, "error logging out of registry that has no entry")

err = suite.Client.Logout(newContext(), suite.DockerRegistryHost)
suite.Nil(err, "no error logging out of registry")
}

func TestDockerClientTestSuite(t *testing.T) {
suite.Run(t, new(DockerClientTestSuite))
}
20 changes: 19 additions & 1 deletion pkg/auth/docker/logout.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
package docker

import "context"
import (
"context"

"github.com/deislabs/oras/pkg/auth"

"github.com/docker/cli/cli/config/configfile"
)

// Logout logs out from a docker registry identified by the hostname.
func (c *Client) Logout(_ context.Context, hostname string) error {
hostname = resolveHostname(hostname)

var configs []*configfile.ConfigFile
for _, config := range c.configs {
if _, ok := config.AuthConfigs[hostname]; ok {
configs = append(configs, config)
}
}
if len(configs) == 0 {
return auth.ErrNotLoggedIn
}

// Log out form the primary config only as backups are read-only.
return c.primaryCredentialsStore(hostname).Erase(hostname)
}

0 comments on commit bc1ed35

Please sign in to comment.