view file/auth_test.go @ 18:00d30c67b56d

Put all the library stuff into multipass/file.
author Paul Fisher <paul@pfish.zone>
date Sun, 01 Nov 2015 12:16:51 -0500
parents auth/auth_test.go@bfc035bd5132
children
line wrap: on
line source

package file

import (
	"regexp"
	"testing"
)

var passPattern *regexp.Regexp = regexp.MustCompile(`^(?:[a-z]{4}-){3}[a-z]{4}$`)

const basicShadow = "9999:$2a$12$tcv2MrtXgibAJHsSwVfHiOevXBFmiGy0HTNoOB8QzIhEh46iWS1uC:YW55dGhpbmcgbW9yZSB0aGFuIDUgcmVwcyBpcyBjYXJkaW8="
const anotherShadow = "1:$2a$12$lINQdYWHOcLKoqhNOr3mNOpZSAu5JOBS2F7T/VDfYn2rvv6qUJehG:"

func TestEntryFromShadow(t *testing.T) {
	cases := []struct {
		shadow      string
		wantErr     bool
		username    string
		id          uint64
		hash        string
		description string
		rest        []string
	}{
		{
			shadow: "1234:$2a$12$apFtWGXKtWBavVy5eo.22Ohs43GudT5IYTqyQkIBX9LpS7YtvKBpa:",
			id:     1234,
			hash:   "$2a$12$apFtWGXKtWBavVy5eo.22Ohs43GudT5IYTqyQkIBX9LpS7YtvKBpa",
		},
		{
			shadow:      basicShadow,
			id:          9999,
			hash:        "$2a$12$tcv2MrtXgibAJHsSwVfHiOevXBFmiGy0HTNoOB8QzIhEh46iWS1uC",
			description: "anything more than 5 reps is cardio",
		},
		{
			shadow: anotherShadow,
			id:     1,
			hash:   "$2a$12$lINQdYWHOcLKoqhNOr3mNOpZSAu5JOBS2F7T/VDfYn2rvv6qUJehG",
		},
		{
			shadow:  "one:bogushash:",
			wantErr: true,
		},
		{
			shadow:  "-1:bogushash:",
			wantErr: true,
		},
		{
			shadow:  "0:tooshort",
			wantErr: true,
		},
		{
			shadow:  "0:bogushash:invalid base64",
			wantErr: true,
		},
		{
			shadow:  "1:bogushash::more things",
			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.id != entry.id {
			t.Errorf("EntryFromShadow(%q).id = %q; want %q", c.shadow, entry.id, c.id)
		}
		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)
		}
	}
}

func TestNewEntry(t *testing.T) {
	cases := []struct {
		description string
		wantErr     bool
	}{
		{"one", false},
		{"the other", false},
		{string(make([]byte, 1000)), true},
	}
	for _, c := range cases {
		entry, password, err := NewEntry(c.description)
		if c.wantErr {
			if err == nil {
				t.Errorf("NewEntry(%q) = _, _, nil; want non-nil err", c.description)
			}
			continue
		}
		if err != nil {
			t.Errorf("NewEntry(%q) = _, _, %q; want nil err", c.description, err)
		}
		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).description = %q, want %q",
				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(password) {
			t.Errorf("NewEntry(%q).Authenticate(%q) failed",
				c.description, 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("")
	if err != nil {
		t.Errorf("Error building entry")
	}
	type testcase struct {
		password string
		want     bool
	}

	cases := []testcase{
		{password, true},
		{"not the password", false},
	}
	for _, c := range cases {
		got := entry.Authenticate(c.password)
		if got != c.want {
			t.Errorf("entry.Authenticate(%q) == %v, want %v",
				c.password, got, c.want)
		}
	}

	entry, err = EntryFromShadow(basicShadow)
	if err != nil {
		t.Errorf("Error loading valid shadow")
	}

	cases = []testcase{
		{"nocardio", true},
		{"not the password", false},
	}
	for _, c := range cases {
		got := entry.Authenticate(c.password)
		if got != c.want {
			t.Errorf("entry.Authenticate(%q) == %v, want %v",
				c.password, got, c.want)
		}
	}
}

func TestEncode(t *testing.T) {
	// Crafted entry
	shadowed, err := EntryFromShadow(basicShadow)
	if err != nil {
		t.Errorf("Error loading valid shadow")
	}
	anotherShadowed, err := EntryFromShadow(anotherShadow)
	if err != nil {
		t.Errorf("Error loading valid shadow")
	}
	cases := []struct {
		entry *Entry
		want  string
	}{
		{
			&Entry{
				id:          6775,
				hash:        "bogushash",
				description: "something",
			},
			"6775:bogushash:c29tZXRoaW5n",
		},
		{shadowed, basicShadow},
		{anotherShadowed, anotherShadow},
	}
	for _, c := range cases {
		got := string(c.entry.Encode())
		if got != c.want {
			t.Errorf("entry.Encode() = %q, want %q", got, c.want)
		}
	}
}