auth

Paddy 2014-11-20 Parent:eb3f2938a319 Child:11ad5eca2f82

80:dfb10e19de87 Go to Latest

auth/oauth2_test.go

Add tests for redirecting to the login page. Make sure that we're redirecting to the configured login page (or returning an error) as expected when trying to obtain a grant code.

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 TestGetGrantCodeLoginRedirect(t *testing.T) {
524 t.Parallel()
525 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
526 if err != nil {
527 t.Fatal("Can't build request:", err)
528 }
529 w := httptest.NewRecorder()
530 GetGrantHandler(w, req, Context{template: template.Must(template.New(getGrantTemplateName).Parse("{{ .internal_error }}"))})
531 if w.Code != http.StatusInternalServerError {
532 t.Errorf("Expected status code to be %d, got %d", http.StatusInternalServerError, w.Code)
533 }
534 expectation := "Missing login URL."
535 if w.Body.String() != expectation {
536 t.Errorf(`Expected body to be "%s", got "%s"`, expectation, w.Body.String())
537 }
538 uri, err := url.Parse("https://client.secondbit.org/")
539 if err != nil {
540 t.Errorf("Unexpected error", err)
541 }
542 testContext := Context{
543 loginURI: uri,
544 }
545 w = httptest.NewRecorder()
546 GetGrantHandler(w, req, testContext)
547 if w.Code != http.StatusFound {
548 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
549 }
550 redirectedTo := w.Header().Get("Location")
551 expectation = "https://client.secondbit.org/?from=https%3A%2F%2Ftest.auth.secondbit.org%2Foauth2%2Fgrant"
552 if redirectedTo != expectation {
553 t.Errorf("Expected to be redirected to '%s', was redirected to '%s'", expectation, redirectedTo)
554 }
555 }
557 func TestGetBasicAuth(t *testing.T) {
558 tests := map[string]struct {
559 un string
560 pass string
561 err error
562 }{
563 "Basic dGVzdHVzZXI6cGFzc3dvcmQx": {"testuser", "password1", nil},
564 "": {"", "", ErrNoAuth},
565 "dGVzdHVzZXI6cGFzc3dvcmQx": {"", "", ErrInvalidAuthFormat},
566 "Basic _*&^##$@#$@&!!@": {"", "", ErrInvalidAuthFormat},
567 "Basic abcdefgh": {"", "", ErrInvalidAuthFormat},
568 "Basic dXNlcjo=": {"user", "", nil},
569 }
571 for header, test := range tests {
572 req, err := http.NewRequest("GET", "https://auth.secondbit.org", nil)
573 if err != nil {
574 t.Error("Unexpected error creating base request:", err)
575 }
576 req.Header.Set("Authorization", header)
577 un, pass, err := getBasicAuth(req)
578 if un != test.un {
579 t.Errorf(`Expected header "%s" to return username "%s", got "%s"`, header, test.un, un)
580 }
581 if pass != test.pass {
582 t.Errorf(`Expected header "%s" to return password "%s", got "%s"`, header, test.pass, pass)
583 }
584 if err != test.err {
585 t.Errorf(`Expected header "%s" to return error "%s", got "%s"`, header, test.err, err)
586 }
587 }
588 }
590 func TestCheckCookie(t *testing.T) {
591 t.Parallel()
592 req, err := http.NewRequest("GET", "https://auth.secondbit.org", nil)
593 if err != nil {
594 t.Error("Unexpected error creating base request:", err)
595 }
596 store := NewMemstore()
597 testContext := Context{
598 sessions: store,
599 }
600 session, err := checkCookie(req, testContext)
601 if err != ErrNoSession {
602 t.Errorf("Expected ErrNoSession, got %s", err)
603 }
604 session = Session{
605 ID: "testsession",
606 Active: true,
607 }
608 err = testContext.CreateSession(session)
609 if err != nil {
610 t.Error("Unexpected error persisting session:", err)
611 }
612 invalidSession := Session{
613 ID: "testsession2",
614 Active: false,
615 }
616 err = testContext.CreateSession(invalidSession)
617 if err != nil {
618 t.Error("Unexpected error persisting session:", err)
619 }
620 result, err := checkCookie(req, testContext)
621 if err != ErrNoSession {
622 t.Errorf("Expected ErrNoSession, got %s", err)
623 }
624 req.AddCookie(&http.Cookie{
625 Name: "wrongcookie",
626 Value: "wrong value",
627 })
628 result, err = checkCookie(req, testContext)
629 if err != ErrNoSession {
630 t.Error("Expected ErrNoSession, got", err)
631 }
632 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
633 if err != nil {
634 t.Error("Unexpected error creating base request:", err)
635 }
636 req.AddCookie(&http.Cookie{
637 Name: "Stillwrongcookie",
638 Value: session.ID,
639 })
640 result, err = checkCookie(req, testContext)
641 if err != ErrNoSession {
642 t.Error("Expected ErrNoSession, got", err)
643 }
644 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
645 if err != nil {
646 t.Error("Unexpected error creating base request:", err)
647 }
648 req.AddCookie(&http.Cookie{
649 Name: authCookieName,
650 Value: "wrong value",
651 })
652 result, err = checkCookie(req, testContext)
653 if err != ErrInvalidSession {
654 t.Error("Expected ErrInvalidSession, got", err)
655 }
656 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
657 if err != nil {
658 t.Error("Unexpected error creating base request:", err)
659 }
660 req.AddCookie(&http.Cookie{
661 Name: authCookieName,
662 Value: invalidSession.ID,
663 })
664 result, err = checkCookie(req, testContext)
665 if err != ErrInvalidSession {
666 t.Error("Expected ErrInvalidSession, got", err)
667 }
668 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
669 if err != nil {
670 t.Error("Unexpected error creating base request:", err)
671 }
672 req.AddCookie(&http.Cookie{
673 Name: authCookieName,
674 Value: session.ID,
675 })
676 result, err = checkCookie(req, testContext)
677 if err != nil {
678 t.Error("Unexpected error:", err)
679 }
680 success, field, expectation, outcome := compareSessions(session, result)
681 if !success {
682 t.Errorf(`Expected field %s to be %v, but got %v`, field, expectation, outcome)
683 }
684 }
686 func TestBuildLoginRedirect(t *testing.T) {
687 t.Parallel()
688 req, err := http.NewRequest("GET", "https://client.secondbit.org/my/awesome/path?has=query&params=to&screw=this&all=up", nil)
689 if err != nil {
690 t.Error("Unexpected error creating base request:", err)
691 }
692 result := buildLoginRedirect(req, Context{})
693 if result != "" {
694 t.Error("Expected empty string as the result, got", result)
695 }
696 uri, err := url.Parse("https://auth.secondbit.org/login?query=string&other=param")
697 if err != nil {
698 t.Error("Unexpected error parsing URL:", err)
699 }
700 c := Context{loginURI: uri}
701 result = buildLoginRedirect(req, c)
702 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"
703 if result != expectation {
704 t.Errorf(`Expected result string to be "%s", was "%s"`, expectation, result)
705 }
706 }
708 func TestAuthenticateHelper(t *testing.T) {
709 t.Parallel()
710 store := NewMemstore()
711 context := Context{
712 profiles: store,
713 }
714 profile := Profile{
715 ID: uuid.NewID(),
716 Name: "Test User",
717 Passphrase: "55d87acb9adff90a0d8e4c9b77f239c2d6e3a1945dbd09b0270467411198db25",
718 Iterations: 4096,
719 Salt: "this is a super secure random salt",
720 PassphraseScheme: 1,
721 Compromised: false,
722 LockedUntil: time.Time{},
723 PassphraseReset: "",
724 PassphraseResetCreated: time.Time{},
725 Created: time.Now(),
726 LastSeen: time.Time{},
727 }
728 login := Login{
729 Type: "email",
730 Value: "test@example.com",
731 ProfileID: profile.ID,
732 Created: time.Now(),
733 LastUsed: time.Time{},
734 }
735 err := context.SaveProfile(profile)
736 if err != nil {
737 t.Error("Error saving profile:", err)
738 }
739 err = context.AddLogin(login)
740 if err != nil {
741 t.Error("Error adding login:", err)
742 }
743 response, err := authenticate("test@example.com", "a really secure password", context)
744 if err != nil {
745 t.Error("Unexpected error:", err)
746 }
747 success, field, expectation, result := compareProfiles(profile, response)
748 if !success {
749 t.Errorf(`Expected field %s to be "%v", got "%v"`, field, expectation, result)
750 }
751 response, err = authenticate("test2@example.com", "a really secure password", context)
752 if err != ErrIncorrectAuth {
753 t.Error("Expected ErrIncorrectAuth, got", err)
754 }
755 response, err = authenticate("test@example.com", "not the right password", context)
756 if err != ErrIncorrectAuth {
757 t.Error("Expected ErrIncorrectAuth, got", err)
758 }
759 scheme := 1000
760 phrase := "doesn't really matter, the scheme doesn't exist"
761 change := ProfileChange{
762 PassphraseScheme: &scheme,
763 Passphrase: &phrase,
764 }
765 err = context.UpdateProfile(profile.ID, change)
766 if err != nil {
767 t.Error("Unexpected error:", err)
768 }
769 response, err = authenticate("test@example.com", "not the right password", context)
770 if err != ErrInvalidPassphraseScheme {
771 t.Error("Expected ErrIncorrectAuth, got", err)
772 }
773 }