Mercurial > go > multipass
diff auth/auth_test.go @ 0:c18bc7b9d1d9
Basic binaries. checkpassword doesn't yet work.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sat, 24 Oct 2015 21:32:03 -0400 |
parents | |
children | 1c194fa9bbf4 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auth/auth_test.go Sat Oct 24 21:32:03 2015 -0400 @@ -0,0 +1,257 @@ +package auth + +import ( + "regexp" + "testing" +) + +var passPattern *regexp.Regexp = regexp.MustCompile(`^(?:[a-z]{4}-){3}[a-z]{4}$`) + +const basicShadow = "jhh:9999:$2a$12$tcv2MrtXgibAJHsSwVfHiOevXBFmiGy0HTNoOB8QzIhEh46iWS1uC:YW55dGhpbmcgbW9yZSB0aGFuIDUgcmVwcyBpcyBjYXJkaW8=" +const extraDataShadow = "skw:1:$2a$12$lINQdYWHOcLKoqhNOr3mNOpZSAu5JOBS2F7T/VDfYn2rvv6qUJehG::additional:fields" + +func TestEntryFromShadow(t *testing.T) { + cases := []struct { + shadow string + wantErr bool + username string + id uint64 + hash string + description string + rest []string + }{ + { + shadow: "pfish:1234:$2a$12$apFtWGXKtWBavVy5eo.22Ohs43GudT5IYTqyQkIBX9LpS7YtvKBpa", + username: "pfish", + id: 1234, + hash: "$2a$12$apFtWGXKtWBavVy5eo.22Ohs43GudT5IYTqyQkIBX9LpS7YtvKBpa", + }, + { + shadow: basicShadow, + username: "jhh", + id: 9999, + hash: "$2a$12$tcv2MrtXgibAJHsSwVfHiOevXBFmiGy0HTNoOB8QzIhEh46iWS1uC", + description: "anything more than 5 reps is cardio", + }, + { + shadow: extraDataShadow, + username: "skw", + id: 1, + hash: "$2a$12$lINQdYWHOcLKoqhNOr3mNOpZSAu5JOBS2F7T/VDfYn2rvv6qUJehG", + rest: []string{"additional", "fields"}, + }, + { + shadow: "user:one:bogushash", + wantErr: true, + }, + { + shadow: "user:-1:bogushash", + wantErr: true, + }, + { + shadow: "tooshort", + wantErr: true, + }, + { + shadow: "test:0:bogushash:invalid base64", + wantErr: true, + }, + } + for _, c := range cases { + entry, err := EntryFromShadow(c.shadow) + if c.wantErr { + if err == nil { + t.Errorf("EntryFromShadow(%q) == _, nil; want non-nil err", c.shadow) + } + continue + } + if err != nil { + t.Errorf("EntryFromShadow(%q) == _, %q; want nil err", c.shadow, err) + } + if c.username != entry.username { + t.Errorf("EntryFromShadow(%q).username = %q; want %q", c.shadow, entry.username, c.username) + } + if c.hash != string(entry.hash) { + t.Errorf("EntryFromShadow(%q).password = %q; want %q", c.shadow, entry.hash, c.hash) + } + if c.description != entry.description { + t.Errorf("EntryFromShadow(%q).description = %q; want %q", c.shadow, entry.description, c.description) + } + restEqual := false + if len(c.rest) == len(entry.rest) { + restEqual = true + for i := range c.rest { + if c.rest[i] != entry.rest[i] { + restEqual = false + break + } + } + } + if !restEqual { + t.Errorf("EntryFromShadow(%q).rest = %q; want %q", c.shadow, entry.rest, c.rest) + } + } +} + +func TestNewEntry(t *testing.T) { + cases := []struct { + username string + description string + wantErr bool + }{ + {"pfish", "one", false}, + {"pfish", "the other", false}, + {"with:colons", "", true}, + {"pfish", string(make([]byte, 1000)), true}, + } + for _, c := range cases { + entry, password, err := NewEntry(c.username, c.description) + if c.wantErr { + if err == nil { + t.Errorf("NewEntry(%q, %q) = _, _, nil; want non-nil err", c.username, c.description) + } + continue + } + if err != nil { + t.Errorf("NewEntry(%q, %q) = _, _, %q; want nil err", c.username, c.description, err) + } + if c.username != entry.username { + t.Errorf("NewEntry(%q, %q).username = %q, want %q", + c.username, c.description, entry.username, c.username) + } + if entry.id == 0 { + // This test has a 1/(2**64) chance of failing! :o + t.Errorf("NewEntry(_, _).id == 0, want nonzero") + } + if c.description != entry.description { + t.Errorf("NewEntry(%q, %q).description = %q, want %q", + c.username, c.description, entry.description, c.description) + } + if !passPattern.MatchString(password) { + t.Errorf("NewEntry(_, _) = _, %q, _; wanted to match xxxx-xxxx-xxxx-xxxx", password) + } + if !entry.Authenticate(c.username, password) { + t.Errorf("NewEntry(%q, %q).Authenticate(%q, %q) failed", + c.username, c.description, c.username, password) + } + } +} + +func TestGenPassword(t *testing.T) { + p := genPassword() + if !passPattern.MatchString(string(p)) { + t.Errorf("genPassword() = %q; wanted to match xxxx-xxxx-xxxx-xxxx", p) + } +} + +func TestAuthenticate(t *testing.T) { + entry, password, err := NewEntry("pfish", "") + if err != nil { + t.Errorf("Error building entry") + } + type testcase struct { + username, password string + want bool + } + + cases := []testcase{ + {"pfish", password, true}, + {"jhh", password, false}, + {"pfish", "not the password", false}, + {"jhh", "not the password", false}, + } + for _, c := range cases { + got := entry.Authenticate(c.username, c.password) + if got != c.want { + t.Errorf("entry.Authenticate(%q, %q) == %q, want %q", + c.username, c.password, got, c.want) + } + } + + entry, err = EntryFromShadow(basicShadow) + if err != nil { + t.Errorf("Error loading valid shadow") + } + + cases = []testcase{ + {"jhh", "nocardio", true}, + {"pfish", "nocardio", false}, + {"jhh", "not the password", false}, + {"pfish", "not the password", false}, + } + for _, c := range cases { + got := entry.Authenticate(c.username, c.password) + if got != c.want { + t.Errorf("entry.Authenticate(%q, %q) == %q, want %q", + c.username, c.password, got, c.want) + } + } +} + +func testMatchesID(t *testing.T) { + entry, err := EntryFromShadow(basicShadow) + if err != nil { + t.Errorf("Error loading valid shadow") + } + cases := []struct { + username string + id uint64 + want bool + }{ + {"jhh", 1234, true}, + {"pfish", 1234, false}, + {"jhh", 9999, false}, + {"pfish", 9999, false}, + } + for _, c := range cases { + got := entry.MatchesID(c.username, c.id) + if got != c.want { + t.Errorf("entry.MatchesID(%q, %q) == %q, want %q", + c.username, c.id, got, c.want) + } + } +} + +func TestEncode(t *testing.T) { + // Crafted entry + shadowed, err := EntryFromShadow(basicShadow) + if err != nil { + t.Errorf("Error loading valid shadow") + } + extraShadowed, err := EntryFromShadow(extraDataShadow) + if err != nil { + t.Errorf("Error loading valid shadow") + } + cases := []struct { + entry *Entry + want string + }{ + { + &Entry{ + username: "testuser", + id: 6775, + hash: "bogushash", + description: "something", + }, + "testuser:6775:bogushash:c29tZXRoaW5n", + }, + { + &Entry{ + username: "testuser", + id: 6775, + hash: "bogushash", + description: "something", + rest: []string{"a", "B"}, + }, + "testuser:6775:bogushash:c29tZXRoaW5n:a:B", + }, + {shadowed, basicShadow}, + {extraShadowed, extraDataShadow}, + } + for _, c := range cases { + got := string(c.entry.Encode()) + if got != c.want { + t.Errorf("entry.Encode() = %q, want %q", got, c.want) + } + } +}