distribution/registry/auth/basic/htpasswd_test.go
Stephen J Day ffd3662982 Harden basic auth implementation
After consideration, the basic authentication implementation has been
simplified to only support bcrypt entries in an htpasswd file. This greatly
increases the security of the implementation by reducing the possibility of
timing attacks and other problems trying to detect the password hash type.

Also, the htpasswd file is only parsed at startup, ensuring that the file can
be edited and not effect ongoing requests. Newly added passwords take effect on
restart. Subsequently, password hash entries are now stored in a map.

Test cases have been modified accordingly.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
2015-06-10 19:38:56 -07:00

85 lines
1.8 KiB
Go

package basic
import (
"fmt"
"reflect"
"strings"
"testing"
)
func TestParseHTPasswd(t *testing.T) {
for _, tc := range []struct {
desc string
input string
err error
entries map[string][]byte
}{
{
desc: "basic example",
input: `
# This is a comment in a basic example.
bilbo:{SHA}5siv5c0SHx681xU6GiSx9ZQryqs=
frodo:$2y$05$926C3y10Quzn/LnqQH86VOEVh/18T6RnLaS.khre96jLNL/7e.K5W
MiShil:$2y$05$0oHgwMehvoe8iAWS8I.7l.KoECXrwVaC16RPfaSCU5eVTFrATuMI2
DeokMan:공주님
`,
entries: map[string][]byte{
"bilbo": []byte("{SHA}5siv5c0SHx681xU6GiSx9ZQryqs="),
"frodo": []byte("$2y$05$926C3y10Quzn/LnqQH86VOEVh/18T6RnLaS.khre96jLNL/7e.K5W"),
"MiShil": []byte("$2y$05$0oHgwMehvoe8iAWS8I.7l.KoECXrwVaC16RPfaSCU5eVTFrATuMI2"),
"DeokMan": []byte("공주님"),
},
},
{
desc: "ensures comments are filtered",
input: `
# asdf:asdf
`,
},
{
desc: "ensure midline hash is not comment",
input: `
asdf:as#df
`,
entries: map[string][]byte{
"asdf": []byte("as#df"),
},
},
{
desc: "ensure midline hash is not comment",
input: `
# A valid comment
valid:entry
asdf
`,
err: fmt.Errorf(`htpasswd: invalid entry at line 4: "asdf"`),
},
} {
entries, err := parseHTPasswd(strings.NewReader(tc.input))
if err != tc.err {
if tc.err == nil {
t.Fatalf("%s: unexpected error: %v", tc.desc, err)
} else {
if err.Error() != tc.err.Error() { // use string equality here.
t.Fatalf("%s: expected error not returned: %v != %v", tc.desc, err, tc.err)
}
}
}
if tc.err != nil {
continue // don't test output
}
// allow empty and nil to be equal
if tc.entries == nil {
tc.entries = map[string][]byte{}
}
if !reflect.DeepEqual(entries, tc.entries) {
t.Fatalf("%s: entries not parsed correctly: %v != %v", tc.desc, entries, tc.entries)
}
}
}