auth

Paddy 2014-09-27 Parent:c6ace3d27c6f Child:d78418fb9f56

47:85f1baf7a9ac Go to Latest

auth/profile_test.go

Add basic test for retrieving profiles by login. Add a basic test for retrieving profiles from ProfileStores by a passed login. The test is very basic, in that it doesn't test for deleted logins, deleted profiles, etc. But it at least tests that in ordinary circumstances, things work as they're supposed to.

History
1 package auth
3 import (
4 "fmt"
5 "testing"
6 "time"
8 "code.secondbit.org/uuid"
9 )
11 const (
12 profileChangeName = 1 << iota
13 profileChangePassphrase
14 profileChangeIterations
15 profileChangeSalt
16 profileChangePassphraseScheme
17 profileChangeCompromised
18 profileChangeLockedUntil
19 profileChangePassphraseReset
20 profileChangePassphraseResetCreated
21 profileChangeLastSeen
22 )
24 var profileStores = []ProfileStore{NewMemstore()}
26 func compareProfiles(profile1, profile2 Profile) (success bool, field string, val1, val2 interface{}) {
27 if !profile1.ID.Equal(profile2.ID) {
28 return false, "ID", profile1.ID, profile2.ID
29 }
30 if profile1.Name != profile2.Name {
31 return false, "name", profile1.Name, profile2.Name
32 }
33 if profile1.Passphrase != profile2.Passphrase {
34 return false, "passphrase", profile1.Passphrase, profile2.Passphrase
35 }
36 if profile1.Iterations != profile2.Iterations {
37 return false, "iterations", profile1.Iterations, profile2.Iterations
38 }
39 if profile1.Salt != profile2.Salt {
40 return false, "salt", profile1.Salt, profile2.Salt
41 }
42 if profile1.PassphraseScheme != profile2.PassphraseScheme {
43 return false, "passphrase scheme", profile1.PassphraseScheme, profile2.PassphraseScheme
44 }
45 if profile1.Compromised != profile2.Compromised {
46 return false, "compromised", profile1.Compromised, profile2.Compromised
47 }
48 if !profile1.LockedUntil.Equal(profile2.LockedUntil) {
49 return false, "locked until", profile1.LockedUntil, profile2.LockedUntil
50 }
51 if profile1.PassphraseReset != profile2.PassphraseReset {
52 return false, "passphrase reset", profile1.PassphraseReset, profile2.PassphraseReset
53 }
54 if !profile1.PassphraseResetCreated.Equal(profile2.PassphraseResetCreated) {
55 return false, "passphrase reset created", profile1.PassphraseResetCreated, profile2.PassphraseResetCreated
56 }
57 if !profile1.Created.Equal(profile2.Created) {
58 return false, "created", profile1.Created, profile2.Created
59 }
60 if !profile1.LastSeen.Equal(profile2.LastSeen) {
61 return false, "last seen", profile1.LastSeen, profile2.LastSeen
62 }
63 return true, "", nil, nil
64 }
66 func compareLogins(login1, login2 Login) (success bool, field string, val1, val2 interface{}) {
67 if login1.Type != login2.Type {
68 return false, "Type", login1.Type, login2.Type
69 }
70 if login1.Value != login2.Value {
71 return false, "Value", login1.Value, login2.Value
72 }
73 if !login1.ProfileID.Equal(login2.ProfileID) {
74 return false, "ProfileID", login1.ProfileID, login2.ProfileID
75 }
76 if !login1.Created.Equal(login2.Created) {
77 return false, "Created", login1.Created, login2.Created
78 }
79 if !login1.LastUsed.Equal(login2.LastUsed) {
80 return false, "LastUsed", login1.LastUsed, login2.LastUsed
81 }
82 return true, "", nil, nil
83 }
85 func TestProfileStoreSuccess(t *testing.T) {
86 t.Parallel()
87 profile := Profile{
88 ID: uuid.NewID(),
89 Name: "name",
90 Passphrase: "passphrase",
91 Iterations: 10000,
92 Salt: "salt",
93 PassphraseScheme: 1,
94 Compromised: false,
95 LockedUntil: time.Now().Add(time.Hour),
96 PassphraseReset: "passphrase reset",
97 PassphraseResetCreated: time.Now(),
98 Created: time.Now(),
99 LastSeen: time.Now(),
100 }
101 for _, store := range profileStores {
102 err := store.SaveProfile(profile)
103 if err != nil {
104 t.Errorf("Error saving profile to %T: %s", store, err)
105 }
106 err = store.SaveProfile(profile)
107 if err != ErrProfileAlreadyExists {
108 t.Errorf("Expected ErrProfileAlreadyExists from %T, got %+v", store, err)
109 }
110 retrieved, err := store.GetProfileByID(profile.ID)
111 if err != nil {
112 t.Errorf("Error retrieving profile from %T: %s", store, err)
113 }
114 match, field, expectation, result := compareProfiles(profile, retrieved)
115 if !match {
116 t.Errorf("Expected `%v` in the `%s` field of profile retrieved from %T, got `%v`", expectation, field, store, result)
117 }
118 err = store.DeleteProfile(profile.ID)
119 if err != nil {
120 t.Errorf("Error removing profile from %T: %s", store, err)
121 }
122 retrieved, err = store.GetProfileByID(profile.ID)
123 if err != ErrProfileNotFound {
124 t.Errorf("Expected ErrProfileNotFound from %T, got %+v and %+v", store, retrieved, err)
125 }
126 err = store.DeleteProfile(profile.ID)
127 if err != ErrProfileNotFound {
128 t.Errorf("Expected ErrProfileNotFound from %T, got %+v", store, err)
129 }
130 }
131 }
133 func TestProfileUpdates(t *testing.T) {
134 t.Parallel()
135 variations := 1 << 10
136 profile := Profile{
137 ID: uuid.NewID(),
138 Name: "name",
139 Passphrase: "passphrase",
140 Iterations: 10000,
141 Salt: "salt",
142 PassphraseScheme: 1,
143 Compromised: false,
144 LockedUntil: time.Now().Add(time.Hour),
145 PassphraseReset: "passphrase reset",
146 PassphraseResetCreated: time.Now(),
147 Created: time.Now(),
148 LastSeen: time.Now(),
149 }
150 for i := 0; i < variations; i++ {
151 var name, passphrase, salt, passphraseReset string
152 var iterations int64
153 var lockedUntil, passphraseResetCreated, lastSeen time.Time
154 var passphraseScheme int
155 var compromised bool
157 change := ProfileChange{}
158 expectation := profile
159 result := profile
160 if i&profileChangeName != 0 {
161 name = fmt.Sprintf("name-%d", i)
162 change.Name = &name
163 expectation.Name = name
164 }
165 if i&profileChangePassphrase != 0 {
166 passphrase = fmt.Sprintf("passphrase-%d", i)
167 change.Passphrase = &passphrase
168 expectation.Passphrase = passphrase
169 }
170 if i&profileChangeIterations != 0 {
171 iterations = int64(i)
172 change.Iterations = &iterations
173 expectation.Iterations = iterations
174 }
175 if i&profileChangeSalt != 0 {
176 salt = fmt.Sprintf("salt-%d", i)
177 change.Salt = &salt
178 expectation.Salt = salt
179 }
180 if i&profileChangePassphraseScheme != 0 {
181 passphraseScheme = i
182 change.PassphraseScheme = &passphraseScheme
183 expectation.PassphraseScheme = passphraseScheme
184 }
185 if i&profileChangeCompromised != 0 {
186 compromised = i%2 != 0
187 change.Compromised = &compromised
188 expectation.Compromised = compromised
189 }
190 if i&profileChangeLockedUntil != 0 {
191 lockedUntil = time.Now()
192 change.LockedUntil = &lockedUntil
193 expectation.LockedUntil = lockedUntil
194 }
195 if i&profileChangePassphraseReset != 0 {
196 passphraseReset = fmt.Sprintf("passphraseReset-%d", i)
197 change.PassphraseReset = &passphraseReset
198 expectation.PassphraseReset = passphraseReset
199 }
200 if i&profileChangePassphraseResetCreated != 0 {
201 passphraseResetCreated = time.Now()
202 change.PassphraseResetCreated = &passphraseResetCreated
203 expectation.PassphraseResetCreated = passphraseResetCreated
204 }
205 if i&profileChangeLastSeen != 0 {
206 lastSeen = time.Now()
207 change.LastSeen = &lastSeen
208 expectation.LastSeen = lastSeen
209 }
210 result.ApplyChange(change)
211 match, field, expected, got := compareProfiles(expectation, result)
212 if !match {
213 t.Errorf("Expected field `%s` to be `%v`, got `%v`", field, expected, got)
214 }
215 for _, store := range profileStores {
216 err := store.SaveProfile(profile)
217 if err != nil {
218 t.Errorf("Error saving profile in %T: %s", store, err)
219 }
220 err = store.UpdateProfile(profile.ID, change)
221 if err != nil {
222 t.Errorf("Error updating profile in %T: %s", store, err)
223 }
224 retrieved, err := store.GetProfileByID(profile.ID)
225 if err != nil {
226 t.Errorf("Error getting profile from %T: %s", store, err)
227 }
228 match, field, expected, got = compareProfiles(expectation, retrieved)
229 if !match {
230 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store)
231 }
232 err = store.DeleteProfile(profile.ID)
233 if err != nil {
234 t.Errorf("Error deleting profile from %T: %s", store, err)
235 }
236 err = store.UpdateProfile(profile.ID, change)
237 if err != ErrProfileNotFound {
238 t.Errorf("Expected ErrProfileNotFound, got %v from %T", err, store)
239 }
240 }
241 }
242 }
244 func TestProfilesUpdates(t *testing.T) {
245 profile1 := Profile{
246 ID: uuid.NewID(),
247 }
248 profile2 := Profile{
249 ID: uuid.NewID(),
250 }
251 profile3 := Profile{
252 ID: uuid.NewID(),
253 }
254 truth := true
255 change := BulkProfileChange{
256 Compromised: &truth,
257 }
258 for _, store := range profileStores {
259 err := store.SaveProfile(profile1)
260 if err != nil {
261 t.Errorf("Error saving profile in %T: %s", store, err)
262 }
263 err = store.SaveProfile(profile2)
264 if err != nil {
265 t.Errorf("Error saving profile in %T: %s", store, err)
266 }
267 err = store.SaveProfile(profile3)
268 if err != nil {
269 t.Errorf("Error saving profile in %T: %s", store, err)
270 }
271 err = store.UpdateProfiles([]uuid.ID{profile1.ID, profile3.ID}, change)
272 if err != nil {
273 t.Errorf("Error updating profile in %T: %s", store, err)
274 }
275 profile1.Compromised = truth
276 profile3.Compromised = truth
277 retrieved, err := store.GetProfileByID(profile1.ID)
278 if err != nil {
279 t.Errorf("Error getting profile from %T: %s", store, err)
280 }
281 match, field, expected, got := compareProfiles(profile1, retrieved)
282 if !match {
283 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store)
284 }
285 retrieved, err = store.GetProfileByID(profile2.ID)
286 if err != nil {
287 t.Errorf("Error getting profile from %T: %s", store, err)
288 }
289 match, field, expected, got = compareProfiles(profile2, retrieved)
290 if !match {
291 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store)
292 }
293 retrieved, err = store.GetProfileByID(profile3.ID)
294 if err != nil {
295 t.Errorf("Error getting profile from %T: %s", store, err)
296 }
297 match, field, expected, got = compareProfiles(profile3, retrieved)
298 if !match {
299 t.Errorf("Expected field `%s` to be `%v`, got `%v` from %T", field, expected, got, store)
300 }
301 }
302 }
304 func TestProfileStoreLoginSuccess(t *testing.T) {
305 t.Parallel()
306 login := Login{
307 Type: "type",
308 Value: "value",
309 ProfileID: uuid.NewID(),
310 Created: time.Now().Add(-1 * time.Hour),
311 LastUsed: time.Now().Add(-1 * time.Minute),
312 }
313 for _, store := range profileStores {
314 err := store.AddLogin(login)
315 if err != nil {
316 t.Errorf("Error adding login to %T: %s", store, err)
317 }
318 err = store.AddLogin(login)
319 if err != ErrLoginAlreadyExists {
320 t.Errorf("Expected ErrLoginAlreadyExists from %T, got %+v", store, err)
321 }
322 retrieved, err := store.ListLogins(login.ProfileID, 10, 0)
323 if err != nil {
324 t.Errorf("Error retrieving logins from %T: %s", store, err)
325 }
326 if len(retrieved) != 1 {
327 t.Errorf("Expected 1 login result from %T, got %d", store, len(retrieved))
328 }
329 match, field, expectation, result := compareLogins(login, retrieved[0])
330 if !match {
331 t.Errorf("Expected `%v` in the `%s` field of login retrieved from %T, got `%v`", expectation, field, store, result)
332 }
333 lastUsed := time.Now()
334 err = store.RecordLoginUse(login.Type, login.Value, lastUsed)
335 if err != nil {
336 t.Errorf("Error recording use of login to %T: %s", store, err)
337 }
338 login.LastUsed = lastUsed
339 retrieved, err = store.ListLogins(login.ProfileID, 10, 0)
340 if err != nil {
341 t.Errorf("Error retrieving logins from %T: %s", store, err)
342 }
343 if len(retrieved) != 1 {
344 t.Errorf("Expected 1 login result from %T, got %d", store, len(retrieved))
345 }
346 match, field, expectation, result = compareLogins(login, retrieved[0])
347 if !match {
348 t.Errorf("Expected `%v` in the `%s` field of login retrieved from %T, got `%v`", expectation, field, store, result)
349 }
350 err = store.RemoveLogin(login.Type, login.Value, login.ProfileID)
351 if err != nil {
352 t.Errorf("Error removing login from %T: %s", store, err)
353 }
354 retrieved, err = store.ListLogins(login.ProfileID, 10, 0)
355 if len(retrieved) != 0 {
356 t.Errorf("Expected 0 login results from %T, got %d: %+v", store, len(retrieved), retrieved)
357 }
358 err = store.RemoveLogin(login.Type, login.Value, login.ProfileID)
359 if err != ErrLoginNotFound {
360 t.Errorf("Expected ErrLoginNotFound from %T, got %+v", store, err)
361 }
362 }
363 }
365 func TestProfileStoreLoginRetrieval(t *testing.T) {
366 t.Parallel()
367 profile := Profile{
368 ID: uuid.NewID(),
369 Name: "name",
370 Passphrase: "passphrase",
371 Iterations: 10000,
372 Salt: "salt",
373 PassphraseScheme: 1,
374 Compromised: false,
375 LockedUntil: time.Now().Add(time.Hour),
376 PassphraseReset: "passphrase reset",
377 PassphraseResetCreated: time.Now(),
378 Created: time.Now(),
379 LastSeen: time.Now(),
380 }
381 login := Login{
382 Type: "type",
383 Value: "value",
384 ProfileID: profile.ID,
385 Created: time.Now().Add(-1 * time.Hour),
386 LastUsed: time.Now().Add(-1 * time.Minute),
387 }
388 for _, store := range profileStores {
389 err := store.SaveProfile(profile)
390 if err != nil {
391 t.Errorf("Error saving profile in %T: %s", store, err)
392 }
393 err = store.AddLogin(login)
394 if err != nil {
395 t.Errorf("Error storing login in %T: %s", store, err)
396 }
397 retrieved, err := store.GetProfileByLogin(login.Type, login.Value)
398 if err != nil {
399 t.Errorf("Error retrieving profile by login from %T: %s", store, err)
400 }
401 match, field, expectation, result := compareProfiles(profile, retrieved)
402 if !match {
403 t.Errorf("Expected `%v` in the `%s` field of profile retrieved from %T, got `%v`", expectation, field, store, result)
404 }
405 }
406 }