auth

Paddy 2014-11-20 Parent:a9936cf794ba Child:dfb10e19de87

79:eb3f2938a319 Go to Latest

auth/oauth2_test.go

Test authentication helper, fix bugs with authentication. Authentication needs to be hex encoded to be stored, so it only makes sense to decode the hex string stored to get the bytes we'll be comparing. Check for ErrLoginNotFound in addition to ErrProfileNotFound. ErrLoginNotFound is more likely to occur, anyways. Add unit tests for our authentication helper to verify it functions as expected.

History
1 package auth
3 import (
4 "bytes"
5 "html/template"
6 "io/ioutil"
7 "net/http"
8 "net/http/httptest"
9 "net/url"
10 "testing"
11 "time"
13 "code.secondbit.org/uuid"
14 )
16 const (
17 scopeSet = 1 << iota
18 stateSet
19 uriSet
20 )
22 func stripParam(param string, u *url.URL) {
23 q := u.Query()
24 q.Del(param)
25 u.RawQuery = q.Encode()
26 }
28 func TestGetGrantCodeSuccess(t *testing.T) {
29 t.Parallel()
30 store := NewMemstore()
31 testContext := Context{
32 template: template.Must(template.New(getGrantTemplateName).Parse("Get auth grant")),
33 clients: store,
34 grants: store,
35 profiles: store,
36 tokens: store,
37 sessions: store,
38 }
39 client := Client{
40 ID: uuid.NewID(),
41 Secret: "super secret!",
42 OwnerID: uuid.NewID(),
43 Name: "My test client",
44 Logo: "https://secondbit.org/logo.png",
45 Website: "https://secondbit.org",
46 Type: "public",
47 }
48 uri, err := url.Parse("https://test.secondbit.org/redirect")
49 if err != nil {
50 t.Fatal("Can't parse URL:", err)
51 }
52 endpoint := Endpoint{
53 ID: uuid.NewID(),
54 ClientID: client.ID,
55 URI: *uri,
56 Added: time.Now(),
57 }
58 err = testContext.SaveClient(client)
59 if err != nil {
60 t.Fatal("Can't store client:", err)
61 }
62 err = testContext.AddEndpoint(client.ID, endpoint)
63 if err != nil {
64 t.Fatal("Can't store endpoint:", err)
65 }
66 session := Session{
67 ID: "testsession",
68 Active: true,
69 }
70 err = testContext.CreateSession(session)
71 if err != nil {
72 t.Fatal("Can't store session:", err)
73 }
74 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
75 if err != nil {
76 t.Fatal("Can't build request:", err)
77 }
78 cookie := &http.Cookie{
79 Name: authCookieName,
80 Value: session.ID,
81 }
82 req.AddCookie(cookie)
83 for i := 0; i < 1<<3; i++ {
84 w := httptest.NewRecorder()
85 params := url.Values{}
86 // see OAuth 2.0 spec, section 4.1.1
87 params.Set("response_type", "code")
88 params.Set("client_id", client.ID.String())
89 if i&uriSet != 0 {
90 params.Set("redirect_uri", endpoint.URI.String())
91 }
92 if i&scopeSet != 0 {
93 params.Set("scope", "testscope")
94 }
95 if i&stateSet != 0 {
96 params.Set("state", "my super secure state string")
97 }
98 req.URL.RawQuery = params.Encode()
99 req.Method = "GET"
100 req.Body = nil
101 req.Header.Del("Content-Type")
102 GetGrantHandler(w, req, testContext)
103 if w.Code != http.StatusOK {
104 t.Errorf("Expected status code to be %d, got %d for %s", http.StatusOK, w.Code, req.URL.String())
105 }
106 if w.Body.String() != "Get auth grant" {
107 t.Errorf("Expected body to be `%s`, got `%s` for %s", "Get auth grant", w.Body.String(), req.URL.String())
108 }
109 req.Method = "POST"
110 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
111 w = httptest.NewRecorder()
112 data := url.Values{}
113 data.Set("grant", "approved")
114 body := bytes.NewBufferString(data.Encode())
115 req.Body = ioutil.NopCloser(body)
116 GetGrantHandler(w, req, testContext)
117 if w.Code != http.StatusFound {
118 t.Errorf("Expected status code to be %d, got %d for %s", http.StatusFound, w.Code, req.URL.String())
119 }
120 redirectedTo := w.Header().Get("Location")
121 red, err := url.Parse(redirectedTo)
122 if err != nil {
123 t.Fatalf(`Being redirected to a non-URL "%s" threw error "%s" for "%s"\n`, redirectedTo, err, req.URL.String())
124 }
125 t.Log("Redirected to", redirectedTo)
126 if red.Query().Get("code") == "" {
127 t.Fatalf(`Expected code param in redirect URL to be set, but it wasn't for %s`, req.URL.String())
128 }
129 if _, err := testContext.GetGrant(red.Query().Get("code")); err != nil {
130 t.Fatalf(`Unexpected error "%s: retrieving the grant "%s" supplied in the redirect URL for %s`, err, red.Query().Get("code"), req.URL.String())
131 }
132 err = testContext.DeleteGrant(red.Query().Get("code"))
133 if err != nil {
134 t.Log(`Unexpected error "%s" deleting grant "%s" for %s`, err, red.Query().Get("code"), req.URL.String())
135 }
136 stripParam("code", red)
137 if red.Query().Get("state") != params.Get("state") {
138 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s" for %s`, params.Get("state"), red.Query().Get("state"), req.URL.String())
139 }
140 stripParam("state", red)
141 if red.String() != endpoint.URI.String() {
142 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String())
143 }
144 }
145 }
147 func TestGetGrantCodeInvalidClient(t *testing.T) {
148 t.Parallel()
149 store := NewMemstore()
150 testContext := Context{
151 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
152 clients: store,
153 grants: store,
154 profiles: store,
155 tokens: store,
156 sessions: store,
157 }
158 client := Client{
159 ID: uuid.NewID(),
160 Secret: "super secret!",
161 OwnerID: uuid.NewID(),
162 Name: "My test client",
163 Type: "public",
164 }
165 err := testContext.SaveClient(client)
166 if err != nil {
167 t.Fatal("Can't store client:", err)
168 }
169 session := Session{
170 ID: "testsession",
171 Active: true,
172 }
173 err = testContext.CreateSession(session)
174 if err != nil {
175 t.Fatal("Can't store session:", err)
176 }
177 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
178 if err != nil {
179 t.Fatal("Can't build request:", err)
180 }
181 w := httptest.NewRecorder()
182 params := url.Values{}
183 params.Set("response_type", "code")
184 params.Set("redirect_uri", "https://test.secondbit.org/")
185 req.URL.RawQuery = params.Encode()
186 cookie := &http.Cookie{
187 Name: authCookieName,
188 Value: session.ID,
189 }
190 req.AddCookie(cookie)
191 GetGrantHandler(w, req, testContext)
192 if w.Code != http.StatusBadRequest {
193 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
194 }
195 if w.Body.String() != "Client ID must be specified in the request." {
196 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "Client ID must be specified in the request.", w.Body.String())
197 }
198 w = httptest.NewRecorder()
199 params.Set("client_id", "Not an ID")
200 req.URL.RawQuery = params.Encode()
201 GetGrantHandler(w, req, testContext)
202 if w.Code != http.StatusBadRequest {
203 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
204 }
205 if w.Body.String() != "client_id is not a valid Client ID." {
206 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "client_id is not a valid Client ID.", w.Body.String())
207 }
208 w = httptest.NewRecorder()
209 params.Set("client_id", uuid.NewID().String())
210 req.URL.RawQuery = params.Encode()
211 GetGrantHandler(w, req, testContext)
212 if w.Code != http.StatusBadRequest {
213 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
214 }
215 if w.Body.String() != "The specified Client couldn&rsquo;t be found." {
216 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The specified Client couldn&rsquo;t be found.", w.Body.String())
217 }
218 }
220 func TestGetGrantCodeInvalidURI(t *testing.T) {
221 t.Parallel()
222 store := NewMemstore()
223 testContext := Context{
224 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
225 clients: store,
226 grants: store,
227 profiles: store,
228 tokens: store,
229 sessions: store,
230 }
231 client := Client{
232 ID: uuid.NewID(),
233 Secret: "super secret!",
234 OwnerID: uuid.NewID(),
235 Name: "My test client",
236 Type: "public",
237 }
238 uri, err := url.Parse("https://test.secondbit.org/redirect")
239 if err != nil {
240 t.Fatal("Can't parse URL:", err)
241 }
242 err = testContext.SaveClient(client)
243 if err != nil {
244 t.Fatal("Can't store client:", err)
245 }
246 session := Session{
247 ID: "testsession",
248 Active: true,
249 }
250 err = testContext.CreateSession(session)
251 if err != nil {
252 t.Fatal("Can't store session:", err)
253 }
254 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
255 if err != nil {
256 t.Fatal("Can't build request:", err)
257 }
258 cookie := &http.Cookie{
259 Name: authCookieName,
260 Value: session.ID,
261 }
262 req.AddCookie(cookie)
263 w := httptest.NewRecorder()
264 params := url.Values{}
265 params.Set("response_type", "code")
266 params.Set("client_id", client.ID.String())
267 req.URL.RawQuery = params.Encode()
268 GetGrantHandler(w, req, testContext)
269 if w.Code != http.StatusBadRequest {
270 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
271 }
272 if w.Body.String() != "The redirect_uri specified is not valid." {
273 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
274 }
275 endpoint := Endpoint{
276 ID: uuid.NewID(),
277 ClientID: client.ID,
278 URI: *uri,
279 Added: time.Now(),
280 }
281 err = testContext.AddEndpoint(client.ID, endpoint)
282 if err != nil {
283 t.Fatal("Can't store endpoint:", err)
284 }
285 w = httptest.NewRecorder()
286 params.Set("redirect_uri", "https://test.secondbit.org/wrong")
287 req.URL.RawQuery = params.Encode()
288 GetGrantHandler(w, req, testContext)
289 if w.Code != http.StatusBadRequest {
290 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
291 }
292 if w.Body.String() != "The redirect_uri specified is not valid." {
293 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
294 }
295 endpoint2 := Endpoint{
296 ID: uuid.NewID(),
297 ClientID: client.ID,
298 URI: *uri,
299 Added: time.Now(),
300 }
301 err = testContext.AddEndpoint(client.ID, endpoint2)
302 if err != nil {
303 t.Fatal("Can't store endpoint:", err)
304 }
305 w = httptest.NewRecorder()
306 params.Set("redirect_uri", "")
307 req.URL.RawQuery = params.Encode()
308 GetGrantHandler(w, req, testContext)
309 if w.Code != http.StatusBadRequest {
310 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
311 }
312 if w.Body.String() != "The redirect_uri specified is not valid." {
313 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
314 }
315 w = httptest.NewRecorder()
316 params.Set("redirect_uri", "://not a URL")
317 req.URL.RawQuery = params.Encode()
318 GetGrantHandler(w, req, testContext)
319 if w.Code != http.StatusBadRequest {
320 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
321 }
322 if w.Body.String() != "The redirect_uri specified is not valid." {
323 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
324 }
325 }
327 func TestGetGrantCodeInvalidResponseType(t *testing.T) {
328 t.Parallel()
329 store := NewMemstore()
330 testContext := Context{
331 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
332 clients: store,
333 grants: store,
334 profiles: store,
335 tokens: store,
336 sessions: store,
337 }
338 client := Client{
339 ID: uuid.NewID(),
340 Secret: "super secret!",
341 OwnerID: uuid.NewID(),
342 Name: "My test client",
343 Logo: "https://secondbit.org/logo.png",
344 Website: "https://secondbit.org",
345 Type: "public",
346 }
347 uri, err := url.Parse("https://test.secondbit.org/redirect")
348 if err != nil {
349 t.Fatal("Can't parse URL:", err)
350 }
351 endpoint := Endpoint{
352 ID: uuid.NewID(),
353 ClientID: client.ID,
354 URI: *uri,
355 Added: time.Now(),
356 }
357 err = testContext.SaveClient(client)
358 if err != nil {
359 t.Fatal("Can't store client:", err)
360 }
361 err = testContext.AddEndpoint(client.ID, endpoint)
362 if err != nil {
363 t.Fatal("Can't store endpoint:", err)
364 }
365 session := Session{
366 ID: "testsession",
367 Active: true,
368 }
369 err = testContext.CreateSession(session)
370 if err != nil {
371 t.Fatal("Can't store session:", err)
372 }
373 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
374 if err != nil {
375 t.Fatal("Can't build request:", err)
376 }
377 cookie := &http.Cookie{
378 Name: authCookieName,
379 Value: session.ID,
380 }
381 req.AddCookie(cookie)
382 params := url.Values{}
383 params.Set("response_type", "totally not code")
384 params.Set("client_id", client.ID.String())
385 params.Set("redirect_uri", endpoint.URI.String())
386 params.Set("scope", "testscope")
387 params.Set("state", "my super secure state string")
388 req.URL.RawQuery = params.Encode()
389 w := httptest.NewRecorder()
390 GetGrantHandler(w, req, testContext)
391 if w.Code != http.StatusFound {
392 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
393 }
394 redirectedTo := w.Header().Get("Location")
395 red, err := url.Parse(redirectedTo)
396 if err != nil {
397 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
398 }
399 if red.Query().Get("error") != "invalid_request" {
400 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error"))
401 }
402 stripParam("error", red)
403 if red.Query().Get("state") != params.Get("state") {
404 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
405 }
406 stripParam("state", red)
407 if red.String() != endpoint.URI.String() {
408 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String())
409 }
410 stripParam("response_type", req.URL)
411 w = httptest.NewRecorder()
412 GetGrantHandler(w, req, testContext)
413 if w.Code != http.StatusFound {
414 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
415 }
416 redirectedTo = w.Header().Get("Location")
417 red, err = url.Parse(redirectedTo)
418 if err != nil {
419 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
420 }
421 if red.Query().Get("error") != "invalid_request" {
422 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error"))
423 }
424 stripParam("error", red)
425 if red.Query().Get("state") != params.Get("state") {
426 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
427 }
428 stripParam("state", red)
429 if red.String() != endpoint.URI.String() {
430 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String())
431 }
432 }
434 func TestGetGrantCodeDenied(t *testing.T) {
435 t.Parallel()
436 store := NewMemstore()
437 testContext := Context{
438 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
439 clients: store,
440 grants: store,
441 profiles: store,
442 tokens: store,
443 sessions: store,
444 }
445 client := Client{
446 ID: uuid.NewID(),
447 Secret: "super secret!",
448 OwnerID: uuid.NewID(),
449 Name: "My test client",
450 Logo: "https://secondbit.org/logo.png",
451 Website: "https://secondbit.org",
452 Type: "public",
453 }
454 uri, err := url.Parse("https://test.secondbit.org/redirect")
455 if err != nil {
456 t.Fatal("Can't parse URL:", err)
457 }
458 endpoint := Endpoint{
459 ID: uuid.NewID(),
460 ClientID: client.ID,
461 URI: *uri,
462 Added: time.Now(),
463 }
464 err = testContext.SaveClient(client)
465 if err != nil {
466 t.Fatal("Can't store client:", err)
467 }
468 err = testContext.AddEndpoint(client.ID, endpoint)
469 if err != nil {
470 t.Fatal("Can't store endpoint:", err)
471 }
472 session := Session{
473 ID: "testsession",
474 Active: true,
475 }
476 err = testContext.CreateSession(session)
477 if err != nil {
478 t.Fatal("Can't store session:", err)
479 }
480 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
481 if err != nil {
482 t.Fatal("Can't build request:", err)
483 }
484 cookie := &http.Cookie{
485 Name: authCookieName,
486 Value: session.ID,
487 }
488 req.AddCookie(cookie)
489 params := url.Values{}
490 params.Set("response_type", "code")
491 params.Set("client_id", client.ID.String())
492 params.Set("redirect_uri", endpoint.URI.String())
493 params.Set("scope", "testscope")
494 params.Set("state", "my super secure state string")
495 data := url.Values{}
496 data.Set("grant", "denied")
497 req.URL.RawQuery = params.Encode()
498 req.Body = ioutil.NopCloser(bytes.NewBufferString(data.Encode()))
499 req.Method = "POST"
500 w := httptest.NewRecorder()
501 GetGrantHandler(w, req, testContext)
502 if w.Code != http.StatusFound {
503 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
504 }
505 redirectedTo := w.Header().Get("Location")
506 red, err := url.Parse(redirectedTo)
507 if err != nil {
508 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
509 }
510 if red.Query().Get("error") != "access_denied" {
511 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "access_denied", red.Query().Get("error"))
512 }
513 stripParam("error", red)
514 if red.Query().Get("state") != params.Get("state") {
515 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
516 }
517 stripParam("state", red)
518 if red.String() != endpoint.URI.String() {
519 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String())
520 }
521 }
523 func TestGetBasicAuth(t *testing.T) {
524 tests := map[string]struct {
525 un string
526 pass string
527 err error
528 }{
529 "Basic dGVzdHVzZXI6cGFzc3dvcmQx": {"testuser", "password1", nil},
530 "": {"", "", ErrNoAuth},
531 "dGVzdHVzZXI6cGFzc3dvcmQx": {"", "", ErrInvalidAuthFormat},
532 "Basic _*&^##$@#$@&!!@": {"", "", ErrInvalidAuthFormat},
533 "Basic abcdefgh": {"", "", ErrInvalidAuthFormat},
534 "Basic dXNlcjo=": {"user", "", nil},
535 }
537 for header, test := range tests {
538 req, err := http.NewRequest("GET", "https://auth.secondbit.org", nil)
539 if err != nil {
540 t.Error("Unexpected error creating base request:", err)
541 }
542 req.Header.Set("Authorization", header)
543 un, pass, err := getBasicAuth(req)
544 if un != test.un {
545 t.Errorf(`Expected header "%s" to return username "%s", got "%s"`, header, test.un, un)
546 }
547 if pass != test.pass {
548 t.Errorf(`Expected header "%s" to return password "%s", got "%s"`, header, test.pass, pass)
549 }
550 if err != test.err {
551 t.Errorf(`Expected header "%s" to return error "%s", got "%s"`, header, test.err, err)
552 }
553 }
554 }
556 func TestCheckCookie(t *testing.T) {
557 t.Parallel()
558 req, err := http.NewRequest("GET", "https://auth.secondbit.org", nil)
559 if err != nil {
560 t.Error("Unexpected error creating base request:", err)
561 }
562 store := NewMemstore()
563 testContext := Context{
564 sessions: store,
565 }
566 session, err := checkCookie(req, testContext)
567 if err != ErrNoSession {
568 t.Errorf("Expected ErrNoSession, got %s", err)
569 }
570 session = Session{
571 ID: "testsession",
572 Active: true,
573 }
574 err = testContext.CreateSession(session)
575 if err != nil {
576 t.Error("Unexpected error persisting session:", err)
577 }
578 invalidSession := Session{
579 ID: "testsession2",
580 Active: false,
581 }
582 err = testContext.CreateSession(invalidSession)
583 if err != nil {
584 t.Error("Unexpected error persisting session:", err)
585 }
586 result, err := checkCookie(req, testContext)
587 if err != ErrNoSession {
588 t.Errorf("Expected ErrNoSession, got %s", err)
589 }
590 req.AddCookie(&http.Cookie{
591 Name: "wrongcookie",
592 Value: "wrong value",
593 })
594 result, err = checkCookie(req, testContext)
595 if err != ErrNoSession {
596 t.Error("Expected ErrNoSession, got", err)
597 }
598 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
599 if err != nil {
600 t.Error("Unexpected error creating base request:", err)
601 }
602 req.AddCookie(&http.Cookie{
603 Name: "Stillwrongcookie",
604 Value: session.ID,
605 })
606 result, err = checkCookie(req, testContext)
607 if err != ErrNoSession {
608 t.Error("Expected ErrNoSession, got", err)
609 }
610 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
611 if err != nil {
612 t.Error("Unexpected error creating base request:", err)
613 }
614 req.AddCookie(&http.Cookie{
615 Name: authCookieName,
616 Value: "wrong value",
617 })
618 result, err = checkCookie(req, testContext)
619 if err != ErrInvalidSession {
620 t.Error("Expected ErrInvalidSession, got", err)
621 }
622 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
623 if err != nil {
624 t.Error("Unexpected error creating base request:", err)
625 }
626 req.AddCookie(&http.Cookie{
627 Name: authCookieName,
628 Value: invalidSession.ID,
629 })
630 result, err = checkCookie(req, testContext)
631 if err != ErrInvalidSession {
632 t.Error("Expected ErrInvalidSession, got", err)
633 }
634 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
635 if err != nil {
636 t.Error("Unexpected error creating base request:", err)
637 }
638 req.AddCookie(&http.Cookie{
639 Name: authCookieName,
640 Value: session.ID,
641 })
642 result, err = checkCookie(req, testContext)
643 if err != nil {
644 t.Error("Unexpected error:", err)
645 }
646 success, field, expectation, outcome := compareSessions(session, result)
647 if !success {
648 t.Errorf(`Expected field %s to be %v, but got %v`, field, expectation, outcome)
649 }
650 }
652 func TestBuildLoginRedirect(t *testing.T) {
653 t.Parallel()
654 req, err := http.NewRequest("GET", "https://client.secondbit.org/my/awesome/path?has=query&params=to&screw=this&all=up", nil)
655 if err != nil {
656 t.Error("Unexpected error creating base request:", err)
657 }
658 result := buildLoginRedirect(req, Context{})
659 if result != "" {
660 t.Error("Expected empty string as the result, got", result)
661 }
662 uri, err := url.Parse("https://auth.secondbit.org/login?query=string&other=param")
663 if err != nil {
664 t.Error("Unexpected error parsing URL:", err)
665 }
666 c := Context{loginURI: uri}
667 result = buildLoginRedirect(req, c)
668 expectation := "https://auth.secondbit.org/login?from=https%3A%2F%2Fclient.secondbit.org%2Fmy%2Fawesome%2Fpath%3Fhas%3Dquery%26params%3Dto%26screw%3Dthis%26all%3Dup&other=param&query=string"
669 if result != expectation {
670 t.Errorf(`Expected result string to be "%s", was "%s"`, expectation, result)
671 }
672 }
674 func TestAuthenticateHelper(t *testing.T) {
675 t.Parallel()
676 store := NewMemstore()
677 context := Context{
678 profiles: store,
679 }
680 profile := Profile{
681 ID: uuid.NewID(),
682 Name: "Test User",
683 Passphrase: "55d87acb9adff90a0d8e4c9b77f239c2d6e3a1945dbd09b0270467411198db25",
684 Iterations: 4096,
685 Salt: "this is a super secure random salt",
686 PassphraseScheme: 1,
687 Compromised: false,
688 LockedUntil: time.Time{},
689 PassphraseReset: "",
690 PassphraseResetCreated: time.Time{},
691 Created: time.Now(),
692 LastSeen: time.Time{},
693 }
694 login := Login{
695 Type: "email",
696 Value: "test@example.com",
697 ProfileID: profile.ID,
698 Created: time.Now(),
699 LastUsed: time.Time{},
700 }
701 err := context.SaveProfile(profile)
702 if err != nil {
703 t.Error("Error saving profile:", err)
704 }
705 err = context.AddLogin(login)
706 if err != nil {
707 t.Error("Error adding login:", err)
708 }
709 response, err := authenticate("test@example.com", "a really secure password", context)
710 if err != nil {
711 t.Error("Unexpected error:", err)
712 }
713 success, field, expectation, result := compareProfiles(profile, response)
714 if !success {
715 t.Errorf(`Expected field %s to be "%v", got "%v"`, field, expectation, result)
716 }
717 response, err = authenticate("test2@example.com", "a really secure password", context)
718 if err != ErrIncorrectAuth {
719 t.Error("Expected ErrIncorrectAuth, got", err)
720 }
721 response, err = authenticate("test@example.com", "not the right password", context)
722 if err != ErrIncorrectAuth {
723 t.Error("Expected ErrIncorrectAuth, got", err)
724 }
725 scheme := 1000
726 phrase := "doesn't really matter, the scheme doesn't exist"
727 change := ProfileChange{
728 PassphraseScheme: &scheme,
729 Passphrase: &phrase,
730 }
731 err = context.UpdateProfile(profile.ID, change)
732 if err != nil {
733 t.Error("Unexpected error:", err)
734 }
735 response, err = authenticate("test@example.com", "not the right password", context)
736 if err != ErrInvalidPassphraseScheme {
737 t.Error("Expected ErrIncorrectAuth, got", err)
738 }
739 }