diff --git a/registry/auth/basic/access.go b/registry/auth/basic/access.go index 81a22b40..0b3e2788 100644 --- a/registry/auth/basic/access.go +++ b/registry/auth/basic/access.go @@ -56,7 +56,7 @@ func (ac *accessController) Authorized(ctx context.Context, accessRecords ...aut return nil, err } - authHeader := req.Header.Get("Authorization") + authHeader := req.Header.Get("Authorization") if authHeader == "" { challenge := challenge{ realm: ac.realm, @@ -68,7 +68,7 @@ func (ac *accessController) Authorized(ctx context.Context, accessRecords ...aut if !ok { return nil, errors.New("Invalid Authorization header") } - + if res, _ := ac.htpasswd.AuthenticateUser(user, pass); !res { challenge := challenge{ realm: ac.realm, diff --git a/registry/auth/basic/access_test.go b/registry/auth/basic/access_test.go index b731675e..62699a63 100644 --- a/registry/auth/basic/access_test.go +++ b/registry/auth/basic/access_test.go @@ -14,13 +14,12 @@ import ( func TestBasicAccessController(t *testing.T) { testRealm := "The-Shire" - testUsers := []string{"bilbo","frodo","MiShil","DeokMan"} - testPasswords := []string{"baggins","baggins","새주","공주님"} + testUsers := []string{"bilbo", "frodo", "MiShil", "DeokMan"} + testPasswords := []string{"baggins", "baggins", "새주", "공주님"} testHtpasswdContent := `bilbo:{SHA}5siv5c0SHx681xU6GiSx9ZQryqs= frodo:$2y$05$926C3y10Quzn/LnqQH86VOEVh/18T6RnLaS.khre96jLNL/7e.K5W MiShil:$2y$05$0oHgwMehvoe8iAWS8I.7l.KoECXrwVaC16RPfaSCU5eVTFrATuMI2 DeokMan:공주님` - tempFile, err := ioutil.TempFile("", "htpasswd-test") if err != nil { @@ -41,9 +40,9 @@ func TestBasicAccessController(t *testing.T) { } tempFile.Close() - + var userNumber = 0 - + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := context.WithValue(nil, "http.request", r) authCtx, err := accessController.Authorized(ctx) @@ -89,12 +88,12 @@ func TestBasicAccessController(t *testing.T) { for i := 0; i < len(testUsers); i++ { userNumber = i req, _ = http.NewRequest("GET", server.URL, nil) - sekrit := testUsers[i]+":"+testPasswords[i] + sekrit := testUsers[i] + ":" + testPasswords[i] credential := "Basic " + base64.StdEncoding.EncodeToString([]byte(sekrit)) req.Header.Set("Authorization", credential) resp, err = client.Do(req) - + if err != nil { t.Fatalf("unexpected error during GET: %v", err) } @@ -105,6 +104,5 @@ func TestBasicAccessController(t *testing.T) { t.Fatalf("unexpected non-success response status: %v != %v for %s %s %s", resp.StatusCode, http.StatusNoContent, testUsers[i], testPasswords[i], credential) } } - } diff --git a/registry/auth/basic/htpasswd.go b/registry/auth/basic/htpasswd.go index 69dae9d8..89e4b749 100644 --- a/registry/auth/basic/htpasswd.go +++ b/registry/auth/basic/htpasswd.go @@ -8,12 +8,12 @@ import ( "os" "regexp" "strings" - + "golang.org/x/crypto/bcrypt" ) // AuthenticationFailureErr - a generic error message for authentication failure to be presented to agent. -var AuthenticationFailureErr = errors.New("Bad username or password") +var ErrAuthenticationFailure = errors.New("Bad username or password") // HTPasswd - holds a path to a system .htpasswd file and the machinery to parse it. type HTPasswd struct { @@ -22,34 +22,44 @@ type HTPasswd struct { } // AuthType represents a particular hash function used in the htpasswd file. -type AuthType int +type AuthType int + const ( - PlainText AuthType = iota + // PlainText - Plain-text password storage (htpasswd -p) + PlainText AuthType = iota + // SHA1 - sha hashed password storage (htpasswd -s) SHA1 + // ApacheMD5 - apr iterated md5 hashing (htpasswd -m) ApacheMD5 + // BCrypt - BCrypt adapative password hashing (htpasswd -B) BCrypt + // Crypt - System crypt() hashes. (htpasswd -d) Crypt ) // String returns a text representation of the AuthType func (at AuthType) String() string { - switch(at) { - case PlainText: return "plaintext" - case SHA1: return "sha1" - case ApacheMD5: return "md5" - case BCrypt: return "bcrypt" - case Crypt: return "system crypt" + switch at { + case PlainText: + return "plaintext" + case SHA1: + return "sha1" + case ApacheMD5: + return "md5" + case BCrypt: + return "bcrypt" + case Crypt: + return "system crypt" } return "unknown" } - // NewHTPasswd - Create a new HTPasswd with the given path to .htpasswd file. func NewHTPasswd(htpath string) *HTPasswd { return &HTPasswd{path: htpath} } -var bcryptPrefixRegexp *regexp.Regexp = regexp.MustCompile(`^\$2[ab]?y\$`) +var bcryptPrefixRegexp = regexp.MustCompile(`^\$2[ab]?y\$`) // GetAuthCredentialType - Inspect an htpasswd file credential and guess the encryption algorithm used. func GetAuthCredentialType(cred string) AuthType { @@ -72,7 +82,6 @@ func GetAuthCredentialType(cred string) AuthType { // AuthenticateUser - Check a given user:password credential against the receiving HTPasswd's file. func (htpasswd *HTPasswd) AuthenticateUser(user string, pwd string) (bool, error) { - // Open the file. in, err := os.Open(htpasswd.path) if err != nil { @@ -94,34 +103,39 @@ func (htpasswd *HTPasswd) AuthenticateUser(user string, pwd string) (bool, error if entry[0] == user { credential := entry[1] credType := GetAuthCredentialType(credential) - switch(credType) { - case SHA1: { + switch credType { + case SHA1: + { sha := sha1.New() sha.Write([]byte(pwd)) hash := base64.StdEncoding.EncodeToString(sha.Sum(nil)) return entry[1][5:] == hash, nil } - case ApacheMD5: { - return false, errors.New(ApacheMD5.String()+" htpasswd hash function not yet supported") + case ApacheMD5: + { + return false, errors.New(ApacheMD5.String() + " htpasswd hash function not yet supported") } - case BCrypt: { - err := bcrypt.CompareHashAndPassword([]byte(credential),[]byte(pwd)) + case BCrypt: + { + err := bcrypt.CompareHashAndPassword([]byte(credential), []byte(pwd)) if err != nil { return false, err } return true, nil } - case Crypt: { - return false, errors.New(Crypt.String()+" htpasswd hash function not yet supported") + case Crypt: + { + return false, errors.New(Crypt.String() + " htpasswd hash function not yet supported") } - case PlainText: { + case PlainText: + { if pwd == credential { return true, nil - } - return false, AuthenticationFailureErr + } + return false, ErrAuthenticationFailure } } } } - return false, AuthenticationFailureErr + return false, ErrAuthenticationFailure }