comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:c18bc7b9d1d9
1 package auth
2
3 import (
4 "regexp"
5 "testing"
6 )
7
8 var passPattern *regexp.Regexp = regexp.MustCompile(`^(?:[a-z]{4}-){3}[a-z]{4}$`)
9
10 const basicShadow = "jhh:9999:$2a$12$tcv2MrtXgibAJHsSwVfHiOevXBFmiGy0HTNoOB8QzIhEh46iWS1uC:YW55dGhpbmcgbW9yZSB0aGFuIDUgcmVwcyBpcyBjYXJkaW8="
11 const extraDataShadow = "skw:1:$2a$12$lINQdYWHOcLKoqhNOr3mNOpZSAu5JOBS2F7T/VDfYn2rvv6qUJehG::additional:fields"
12
13 func TestEntryFromShadow(t *testing.T) {
14 cases := []struct {
15 shadow string
16 wantErr bool
17 username string
18 id uint64
19 hash string
20 description string
21 rest []string
22 }{
23 {
24 shadow: "pfish:1234:$2a$12$apFtWGXKtWBavVy5eo.22Ohs43GudT5IYTqyQkIBX9LpS7YtvKBpa",
25 username: "pfish",
26 id: 1234,
27 hash: "$2a$12$apFtWGXKtWBavVy5eo.22Ohs43GudT5IYTqyQkIBX9LpS7YtvKBpa",
28 },
29 {
30 shadow: basicShadow,
31 username: "jhh",
32 id: 9999,
33 hash: "$2a$12$tcv2MrtXgibAJHsSwVfHiOevXBFmiGy0HTNoOB8QzIhEh46iWS1uC",
34 description: "anything more than 5 reps is cardio",
35 },
36 {
37 shadow: extraDataShadow,
38 username: "skw",
39 id: 1,
40 hash: "$2a$12$lINQdYWHOcLKoqhNOr3mNOpZSAu5JOBS2F7T/VDfYn2rvv6qUJehG",
41 rest: []string{"additional", "fields"},
42 },
43 {
44 shadow: "user:one:bogushash",
45 wantErr: true,
46 },
47 {
48 shadow: "user:-1:bogushash",
49 wantErr: true,
50 },
51 {
52 shadow: "tooshort",
53 wantErr: true,
54 },
55 {
56 shadow: "test:0:bogushash:invalid base64",
57 wantErr: true,
58 },
59 }
60 for _, c := range cases {
61 entry, err := EntryFromShadow(c.shadow)
62 if c.wantErr {
63 if err == nil {
64 t.Errorf("EntryFromShadow(%q) == _, nil; want non-nil err", c.shadow)
65 }
66 continue
67 }
68 if err != nil {
69 t.Errorf("EntryFromShadow(%q) == _, %q; want nil err", c.shadow, err)
70 }
71 if c.username != entry.username {
72 t.Errorf("EntryFromShadow(%q).username = %q; want %q", c.shadow, entry.username, c.username)
73 }
74 if c.hash != string(entry.hash) {
75 t.Errorf("EntryFromShadow(%q).password = %q; want %q", c.shadow, entry.hash, c.hash)
76 }
77 if c.description != entry.description {
78 t.Errorf("EntryFromShadow(%q).description = %q; want %q", c.shadow, entry.description, c.description)
79 }
80 restEqual := false
81 if len(c.rest) == len(entry.rest) {
82 restEqual = true
83 for i := range c.rest {
84 if c.rest[i] != entry.rest[i] {
85 restEqual = false
86 break
87 }
88 }
89 }
90 if !restEqual {
91 t.Errorf("EntryFromShadow(%q).rest = %q; want %q", c.shadow, entry.rest, c.rest)
92 }
93 }
94 }
95
96 func TestNewEntry(t *testing.T) {
97 cases := []struct {
98 username string
99 description string
100 wantErr bool
101 }{
102 {"pfish", "one", false},
103 {"pfish", "the other", false},
104 {"with:colons", "", true},
105 {"pfish", string(make([]byte, 1000)), true},
106 }
107 for _, c := range cases {
108 entry, password, err := NewEntry(c.username, c.description)
109 if c.wantErr {
110 if err == nil {
111 t.Errorf("NewEntry(%q, %q) = _, _, nil; want non-nil err", c.username, c.description)
112 }
113 continue
114 }
115 if err != nil {
116 t.Errorf("NewEntry(%q, %q) = _, _, %q; want nil err", c.username, c.description, err)
117 }
118 if c.username != entry.username {
119 t.Errorf("NewEntry(%q, %q).username = %q, want %q",
120 c.username, c.description, entry.username, c.username)
121 }
122 if entry.id == 0 {
123 // This test has a 1/(2**64) chance of failing! :o
124 t.Errorf("NewEntry(_, _).id == 0, want nonzero")
125 }
126 if c.description != entry.description {
127 t.Errorf("NewEntry(%q, %q).description = %q, want %q",
128 c.username, c.description, entry.description, c.description)
129 }
130 if !passPattern.MatchString(password) {
131 t.Errorf("NewEntry(_, _) = _, %q, _; wanted to match xxxx-xxxx-xxxx-xxxx", password)
132 }
133 if !entry.Authenticate(c.username, password) {
134 t.Errorf("NewEntry(%q, %q).Authenticate(%q, %q) failed",
135 c.username, c.description, c.username, password)
136 }
137 }
138 }
139
140 func TestGenPassword(t *testing.T) {
141 p := genPassword()
142 if !passPattern.MatchString(string(p)) {
143 t.Errorf("genPassword() = %q; wanted to match xxxx-xxxx-xxxx-xxxx", p)
144 }
145 }
146
147 func TestAuthenticate(t *testing.T) {
148 entry, password, err := NewEntry("pfish", "")
149 if err != nil {
150 t.Errorf("Error building entry")
151 }
152 type testcase struct {
153 username, password string
154 want bool
155 }
156
157 cases := []testcase{
158 {"pfish", password, true},
159 {"jhh", password, false},
160 {"pfish", "not the password", false},
161 {"jhh", "not the password", false},
162 }
163 for _, c := range cases {
164 got := entry.Authenticate(c.username, c.password)
165 if got != c.want {
166 t.Errorf("entry.Authenticate(%q, %q) == %q, want %q",
167 c.username, c.password, got, c.want)
168 }
169 }
170
171 entry, err = EntryFromShadow(basicShadow)
172 if err != nil {
173 t.Errorf("Error loading valid shadow")
174 }
175
176 cases = []testcase{
177 {"jhh", "nocardio", true},
178 {"pfish", "nocardio", false},
179 {"jhh", "not the password", false},
180 {"pfish", "not the password", false},
181 }
182 for _, c := range cases {
183 got := entry.Authenticate(c.username, c.password)
184 if got != c.want {
185 t.Errorf("entry.Authenticate(%q, %q) == %q, want %q",
186 c.username, c.password, got, c.want)
187 }
188 }
189 }
190
191 func testMatchesID(t *testing.T) {
192 entry, err := EntryFromShadow(basicShadow)
193 if err != nil {
194 t.Errorf("Error loading valid shadow")
195 }
196 cases := []struct {
197 username string
198 id uint64
199 want bool
200 }{
201 {"jhh", 1234, true},
202 {"pfish", 1234, false},
203 {"jhh", 9999, false},
204 {"pfish", 9999, false},
205 }
206 for _, c := range cases {
207 got := entry.MatchesID(c.username, c.id)
208 if got != c.want {
209 t.Errorf("entry.MatchesID(%q, %q) == %q, want %q",
210 c.username, c.id, got, c.want)
211 }
212 }
213 }
214
215 func TestEncode(t *testing.T) {
216 // Crafted entry
217 shadowed, err := EntryFromShadow(basicShadow)
218 if err != nil {
219 t.Errorf("Error loading valid shadow")
220 }
221 extraShadowed, err := EntryFromShadow(extraDataShadow)
222 if err != nil {
223 t.Errorf("Error loading valid shadow")
224 }
225 cases := []struct {
226 entry *Entry
227 want string
228 }{
229 {
230 &Entry{
231 username: "testuser",
232 id: 6775,
233 hash: "bogushash",
234 description: "something",
235 },
236 "testuser:6775:bogushash:c29tZXRoaW5n",
237 },
238 {
239 &Entry{
240 username: "testuser",
241 id: 6775,
242 hash: "bogushash",
243 description: "something",
244 rest: []string{"a", "B"},
245 },
246 "testuser:6775:bogushash:c29tZXRoaW5n:a:B",
247 },
248 {shadowed, basicShadow},
249 {extraShadowed, extraDataShadow},
250 }
251 for _, c := range cases {
252 got := string(c.entry.Encode())
253 if got != c.want {
254 t.Errorf("entry.Encode() = %q, want %q", got, c.want)
255 }
256 }
257 }