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)
+		}
+	}
+}