diff --git a/docs/auth/auth.go b/docs/auth/auth.go index 0ba2eba3..0164246c 100644 --- a/docs/auth/auth.go +++ b/docs/auth/auth.go @@ -33,6 +33,7 @@ package auth import ( + "errors" "fmt" "net/http" @@ -49,6 +50,14 @@ const ( UserNameKey = "auth.user.name" ) +var ( + // ErrInvalidCredential is returned when the auth token does not authenticate correctly. + ErrInvalidCredential = errors.New("invalid authorization credential") + + // ErrAuthenticationFailure returned when authentication failure to be presented to agent. + ErrAuthenticationFailure = errors.New("authentication failure") +) + // UserInfo carries information about // an autenticated/authorized client. type UserInfo struct { @@ -97,6 +106,11 @@ type AccessController interface { Authorized(ctx context.Context, access ...Access) (context.Context, error) } +// CredentialAuthenticator is an object which is able to validate credentials +type CredentialAuthenticator interface { + AuthenticateUser(username, password string) error +} + // WithUser returns a context with the authorized user info. func WithUser(ctx context.Context, user UserInfo) context.Context { return userInfoContext{ diff --git a/docs/auth/htpasswd/access.go b/docs/auth/htpasswd/access.go index 6e7ba180..4f71dc27 100644 --- a/docs/auth/htpasswd/access.go +++ b/docs/auth/htpasswd/access.go @@ -6,7 +6,6 @@ package htpasswd import ( - "errors" "fmt" "net/http" "os" @@ -15,14 +14,6 @@ import ( "github.com/docker/distribution/registry/auth" ) -var ( - // ErrInvalidCredential is returned when the auth token does not authenticate correctly. - ErrInvalidCredential = errors.New("invalid authorization credential") - - // ErrAuthenticationFailure returned when authentication failure to be presented to agent. - ErrAuthenticationFailure = errors.New("authentication failure") -) - type accessController struct { realm string htpasswd *htpasswd @@ -65,21 +56,25 @@ func (ac *accessController) Authorized(ctx context.Context, accessRecords ...aut if !ok { return nil, &challenge{ realm: ac.realm, - err: ErrInvalidCredential, + err: auth.ErrInvalidCredential, } } - if err := ac.htpasswd.authenticateUser(username, password); err != nil { + if err := ac.AuthenticateUser(username, password); err != nil { context.GetLogger(ctx).Errorf("error authenticating user %q: %v", username, err) return nil, &challenge{ realm: ac.realm, - err: ErrAuthenticationFailure, + err: auth.ErrAuthenticationFailure, } } return auth.WithUser(ctx, auth.UserInfo{Name: username}), nil } +func (ac *accessController) AuthenticateUser(username, password string) error { + return ac.htpasswd.authenticateUser(username, password) +} + // challenge implements the auth.Challenge interface. type challenge struct { realm string diff --git a/docs/auth/htpasswd/htpasswd.go b/docs/auth/htpasswd/htpasswd.go index 494ad0a7..83f797f7 100644 --- a/docs/auth/htpasswd/htpasswd.go +++ b/docs/auth/htpasswd/htpasswd.go @@ -6,6 +6,8 @@ import ( "io" "strings" + "github.com/docker/distribution/registry/auth" + "golang.org/x/crypto/bcrypt" ) @@ -33,12 +35,12 @@ func (htpasswd *htpasswd) authenticateUser(username string, password string) err // timing attack paranoia bcrypt.CompareHashAndPassword([]byte{}, []byte(password)) - return ErrAuthenticationFailure + return auth.ErrAuthenticationFailure } err := bcrypt.CompareHashAndPassword([]byte(credentials), []byte(password)) if err != nil { - return ErrAuthenticationFailure + return auth.ErrAuthenticationFailure } return nil