Fix tests for scopeStore.
Update all our tests to use the PG_TEST_DB environment variable if set, and use
that to control whether or not the postgres tests get run. testing.Short() just
wasn't working.
Update ErrScopeNotFound and ErrScopeAlreadyExists to be variables instead of
types, because PostgreSQL (annoyingly) offers no way to determine which specific
row insertion caused the problem, and I anticipate this being a problem that is
ongoing. So it's really just not worth it.
Stop getScopes from returning an ErrScopeNotFound. Let's return what we find,
and let the absence of what we didn't find speak for itself.
Fix an error with generating the SQL for the postgres.createScopes call. We used
to generate it in a way that was invalid (not joining values with ",") when more
than one set of values was supplied. Hooray, testing!
Update the postgres scopeStore to return ErrScopeNotFound and
ErrScopeAlreadyExists errors, as appropriate.
Update our tests to reflect that ErrScopeNotFound and ErrScopeAlreadyExists are
now variables, not types.
14 "code.secondbit.org/uuid.hg"
22 func stripParam(param string, u *url.URL) {
25 u.RawQuery = q.Encode()
28 func TestGetAuthorizationCodeCodeSuccess(t *testing.T) {
30 store := NewMemstore()
31 testContext := Context{
32 template: template.Must(template.New(getAuthorizationCodeTemplateName).Parse("{{ if not .error }}Get auth grant{{ else }}{{ .error }}{{ end }}")),
42 Secret: "super secret!",
43 OwnerID: uuid.NewID(),
44 Name: "My test client",
45 Logo: "https://secondbit.org/logo.png",
46 Website: "https://secondbit.org",
52 URI: "https://test.secondbit.org/redirect",
53 Added: time.Now().Round(time.Millisecond),
55 err := testContext.SaveClient(client)
57 t.Fatal("Can't store client:", err)
59 err = testContext.AddEndpoints([]Endpoint{endpoint})
61 t.Fatal("Can't store endpoint:", err)
66 err = testContext.SaveProfile(profile)
68 t.Fatal("Can't store profile:", err)
73 ProfileID: profile.ID,
75 Expires: time.Now().Round(time.Millisecond).Add(time.Hour),
77 err = testContext.CreateSession(session)
79 t.Fatal("Can't store session:", err)
84 Description: "Hug dispensation.",
86 err = testContext.CreateScopes([]Scope{scope})
88 t.Fatal("Can't store scope:", err)
90 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
92 t.Fatal("Can't build request:", err)
94 cookie := &http.Cookie{
99 for i := 0; i < 1<<2; i++ {
100 w := httptest.NewRecorder()
101 params := url.Values{}
102 // see OAuth 2.0 spec, section 4.1.1
103 params.Set("response_type", "code")
104 params.Set("client_id", client.ID.String())
105 params.Set("scope", "testscope")
107 params.Set("redirect_uri", endpoint.URI)
110 params.Set("state", "my super secure state string")
112 req.URL.RawQuery = params.Encode()
115 req.Header.Del("Content-Type")
116 GetAuthorizationCodeHandler(w, req, testContext)
117 if w.Code != http.StatusOK {
118 t.Log("Response body:", w.Body.String())
119 t.Errorf("Expected status code to be %d, got %d for %s", http.StatusOK, w.Code, req.URL.String())
121 if w.Body.String() != "Get auth grant" {
122 t.Errorf("Expected body to be `%s`, got `%s` for %s", "Get auth grant", w.Body.String(), req.URL.String())
125 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
126 w = httptest.NewRecorder()
128 data.Set("grant", "approved")
129 data.Set("csrftoken", session.CSRFToken)
130 body := bytes.NewBufferString(data.Encode())
131 req.Body = ioutil.NopCloser(body)
132 GetAuthorizationCodeHandler(w, req, testContext)
133 if w.Code != http.StatusFound {
134 t.Errorf("Expected status code to be %d, got %d for %s", http.StatusFound, w.Code, req.URL.String())
136 redirectedTo := w.Header().Get("Location")
137 red, err := url.Parse(redirectedTo)
139 t.Fatalf(`Being redirected to a non-URL "%s" threw error "%s" for "%s"\n`, redirectedTo, err, req.URL.String())
141 t.Log("Redirected to", redirectedTo)
142 t.Log("Body", w.Body.String())
143 if red.Query().Get("code") == "" {
144 t.Fatalf(`Expected code param in redirect URL to be set, but it wasn't for %s`, req.URL.String())
146 if _, err := testContext.GetAuthorizationCode(red.Query().Get("code")); err != nil {
147 t.Fatalf(`Unexpected error "%s: retrieving the grant "%s" supplied in the redirect URL for %s`, err, red.Query().Get("code"), req.URL.String())
149 err = testContext.DeleteAuthorizationCode(red.Query().Get("code"))
151 t.Logf(`Unexpected error "%s" deleting grant "%s" for %s`, err, red.Query().Get("code"), req.URL.String())
153 stripParam("code", red)
154 if red.Query().Get("state") != params.Get("state") {
155 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())
157 stripParam("state", red)
158 if red.String() != endpoint.URI {
159 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI, red.String())
164 func TestGetAuthorizationCodeCodeInvalidClient(t *testing.T) {
166 store := NewMemstore()
167 testContext := Context{
168 template: template.Must(template.New(getAuthorizationCodeTemplateName).Parse("{{ .error }}")),
177 Secret: "super secret!",
178 OwnerID: uuid.NewID(),
179 Name: "My test client",
182 err := testContext.SaveClient(client)
184 t.Fatal("Can't store client:", err)
190 Expires: time.Now().Round(time.Millisecond).Add(time.Hour),
192 err = testContext.CreateSession(session)
194 t.Fatal("Can't store session:", err)
196 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
198 t.Fatal("Can't build request:", err)
200 w := httptest.NewRecorder()
201 params := url.Values{}
202 params.Set("response_type", "code")
203 params.Set("redirect_uri", "https://test.secondbit.org/")
204 req.URL.RawQuery = params.Encode()
205 cookie := &http.Cookie{
206 Name: authCookieName,
209 req.AddCookie(cookie)
210 GetAuthorizationCodeHandler(w, req, testContext)
211 if w.Code != http.StatusBadRequest {
212 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
214 if w.Body.String() != "Client ID must be specified in the request." {
215 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "Client ID must be specified in the request.", w.Body.String())
217 w = httptest.NewRecorder()
218 params.Set("client_id", "Not an ID")
219 req.URL.RawQuery = params.Encode()
220 GetAuthorizationCodeHandler(w, req, testContext)
221 if w.Code != http.StatusBadRequest {
222 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
224 if w.Body.String() != "client_id is not a valid Client ID." {
225 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "client_id is not a valid Client ID.", w.Body.String())
227 w = httptest.NewRecorder()
228 params.Set("client_id", uuid.NewID().String())
229 req.URL.RawQuery = params.Encode()
230 GetAuthorizationCodeHandler(w, req, testContext)
231 if w.Code != http.StatusBadRequest {
232 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
234 if w.Body.String() != "The specified Client couldn’t be found." {
235 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The specified Client couldn’t be found.", w.Body.String())
239 func TestGetAuthorizationCodeCodeInvalidURI(t *testing.T) {
241 store := NewMemstore()
242 testContext := Context{
243 template: template.Must(template.New(getAuthorizationCodeTemplateName).Parse("{{ .error }}")),
252 Secret: "super secret!",
253 OwnerID: uuid.NewID(),
254 Name: "My test client",
257 err := testContext.SaveClient(client)
259 t.Fatal("Can't store client:", err)
265 Expires: time.Now().Round(time.Millisecond).Add(time.Hour),
267 err = testContext.CreateSession(session)
269 t.Fatal("Can't store session:", err)
271 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
273 t.Fatal("Can't build request:", err)
275 cookie := &http.Cookie{
276 Name: authCookieName,
279 req.AddCookie(cookie)
280 w := httptest.NewRecorder()
281 params := url.Values{}
282 params.Set("response_type", "code")
283 params.Set("client_id", client.ID.String())
284 req.URL.RawQuery = params.Encode()
285 GetAuthorizationCodeHandler(w, req, testContext)
286 if w.Code != http.StatusBadRequest {
287 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
289 if w.Body.String() != "The redirect_uri specified is not valid." {
290 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
292 endpoint := Endpoint{
295 URI: "https://test.secondbit.org/redirect",
296 Added: time.Now().Round(time.Millisecond),
298 err = testContext.AddEndpoints([]Endpoint{endpoint})
300 t.Fatal("Can't store endpoint:", err)
302 w = httptest.NewRecorder()
303 params.Set("redirect_uri", "https://test.secondbit.org/wrong")
304 req.URL.RawQuery = params.Encode()
305 GetAuthorizationCodeHandler(w, req, testContext)
306 if w.Code != http.StatusBadRequest {
307 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
309 if w.Body.String() != "The redirect_uri specified is not valid." {
310 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
312 endpoint2 := Endpoint{
315 URI: "https://test.secondbit.org/redirect",
316 Added: time.Now().Round(time.Millisecond),
318 err = testContext.AddEndpoints([]Endpoint{endpoint2})
320 t.Fatal("Can't store endpoint:", err)
322 w = httptest.NewRecorder()
323 params.Set("redirect_uri", "")
324 req.URL.RawQuery = params.Encode()
325 GetAuthorizationCodeHandler(w, req, testContext)
326 if w.Code != http.StatusBadRequest {
327 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
329 if w.Body.String() != "The redirect_uri specified is not valid." {
330 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
332 w = httptest.NewRecorder()
333 params.Set("redirect_uri", "://not a URL")
334 req.URL.RawQuery = params.Encode()
335 GetAuthorizationCodeHandler(w, req, testContext)
336 if w.Code != http.StatusBadRequest {
337 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
339 if w.Body.String() != "The redirect_uri specified is not valid." {
340 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
342 // BUG(paddy): Need to test that setting redirect_uri to a non-URL redirect_uri returns the correct error.
345 func TestGetAuthorizationCodeCodeInvalidResponseType(t *testing.T) {
347 store := NewMemstore()
348 testContext := Context{
349 template: template.Must(template.New(getAuthorizationCodeTemplateName).Parse("{{ .error }}")),
358 Secret: "super secret!",
359 OwnerID: uuid.NewID(),
360 Name: "My test client",
361 Logo: "https://secondbit.org/logo.png",
362 Website: "https://secondbit.org",
365 endpoint := Endpoint{
368 URI: "https://test.secondbit.org/redirect",
369 Added: time.Now().Round(time.Millisecond),
371 err := testContext.SaveClient(client)
373 t.Fatal("Can't store client:", err)
375 err = testContext.AddEndpoints([]Endpoint{endpoint})
377 t.Fatal("Can't store endpoint:", err)
383 Expires: time.Now().Round(time.Millisecond).Add(time.Hour),
385 err = testContext.CreateSession(session)
387 t.Fatal("Can't store session:", err)
389 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
391 t.Fatal("Can't build request:", err)
393 cookie := &http.Cookie{
394 Name: authCookieName,
397 req.AddCookie(cookie)
398 params := url.Values{}
399 params.Set("response_type", "totally not code")
400 params.Set("client_id", client.ID.String())
401 params.Set("redirect_uri", endpoint.URI)
402 params.Set("scope", "testscope")
403 params.Set("state", "my super secure state string")
404 req.URL.RawQuery = params.Encode()
405 w := httptest.NewRecorder()
406 GetAuthorizationCodeHandler(w, req, testContext)
407 if w.Code != http.StatusFound {
408 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
410 redirectedTo := w.Header().Get("Location")
411 red, err := url.Parse(redirectedTo)
413 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
415 if red.Query().Get("error") != "invalid_request" {
416 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error"))
418 stripParam("error", red)
419 if red.Query().Get("state") != params.Get("state") {
420 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
422 stripParam("state", red)
423 if red.String() != endpoint.URI {
424 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI, red.String())
426 stripParam("response_type", req.URL)
427 w = httptest.NewRecorder()
428 GetAuthorizationCodeHandler(w, req, testContext)
429 if w.Code != http.StatusFound {
430 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
432 redirectedTo = w.Header().Get("Location")
433 red, err = url.Parse(redirectedTo)
435 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
437 if red.Query().Get("error") != "invalid_request" {
438 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error"))
440 stripParam("error", red)
441 if red.Query().Get("state") != params.Get("state") {
442 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
444 stripParam("state", red)
445 if red.String() != endpoint.URI {
446 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI, red.String())
450 func TestGetAuthorizationCodeCodeDenied(t *testing.T) {
452 store := NewMemstore()
453 testContext := Context{
454 template: template.Must(template.New(getAuthorizationCodeTemplateName).Parse("{{ .error }}")),
464 Secret: "super secret!",
465 OwnerID: uuid.NewID(),
466 Name: "My test client",
467 Logo: "https://secondbit.org/logo.png",
468 Website: "https://secondbit.org",
471 endpoint := Endpoint{
474 URI: "https://test.secondbit.org/redirect",
475 Added: time.Now().Round(time.Millisecond),
477 err := testContext.SaveClient(client)
479 t.Fatal("Can't store client:", err)
481 err = testContext.AddEndpoints([]Endpoint{endpoint})
483 t.Fatal("Can't store endpoint:", err)
489 Expires: time.Now().Round(time.Millisecond).Add(time.Hour),
491 err = testContext.CreateSession(session)
493 t.Fatal("Can't store session:", err)
498 Description: "High five fabrication.",
500 err = testContext.CreateScopes([]Scope{scope})
502 t.Fatal("Can't create scope:", err)
504 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
506 t.Fatal("Can't build request:", err)
508 cookie := &http.Cookie{
509 Name: authCookieName,
512 req.AddCookie(cookie)
513 params := url.Values{}
514 params.Set("response_type", "code")
515 params.Set("client_id", client.ID.String())
516 params.Set("redirect_uri", endpoint.URI)
517 params.Set("scope", "testscope")
518 params.Set("state", "my super secure state string")
520 data.Set("grant", "denied")
521 data.Set("csrftoken", session.CSRFToken)
522 req.URL.RawQuery = params.Encode()
523 req.Body = ioutil.NopCloser(bytes.NewBufferString(data.Encode()))
524 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
526 w := httptest.NewRecorder()
527 GetAuthorizationCodeHandler(w, req, testContext)
528 if w.Code != http.StatusFound {
529 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
531 redirectedTo := w.Header().Get("Location")
532 red, err := url.Parse(redirectedTo)
534 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
536 if red.Query().Get("error") != "access_denied" {
537 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "access_denied", red.Query().Get("error"))
539 stripParam("error", red)
540 if red.Query().Get("state") != params.Get("state") {
541 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
543 stripParam("state", red)
544 if red.String() != endpoint.URI {
545 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI, red.String())
549 func TestGetAuthorizationCodeCodeLoginRedirect(t *testing.T) {
551 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
553 t.Fatal("Can't build request:", err)
555 w := httptest.NewRecorder()
556 GetAuthorizationCodeHandler(w, req, Context{template: template.Must(template.New(getAuthorizationCodeTemplateName).Parse("{{ .internal_error }}"))})
557 if w.Code != http.StatusInternalServerError {
558 t.Errorf("Expected status code to be %d, got %d", http.StatusInternalServerError, w.Code)
560 expectation := "Missing login URL."
561 if w.Body.String() != expectation {
562 t.Errorf(`Expected body to be "%s", got "%s"`, expectation, w.Body.String())
564 uri, err := url.Parse("https://client.secondbit.org/")
566 t.Error("Unexpected error", err)
568 testContext := Context{
571 w = httptest.NewRecorder()
572 GetAuthorizationCodeHandler(w, req, testContext)
573 if w.Code != http.StatusFound {
574 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
576 redirectedTo := w.Header().Get("Location")
577 expectation = "https://client.secondbit.org/?from=https%3A%2F%2Ftest.auth.secondbit.org%2Foauth2%2Fgrant"
578 if redirectedTo != expectation {
579 t.Errorf("Expected to be redirected to '%s', was redirected to '%s'", expectation, redirectedTo)
583 // BUG(paddy): Need to test for implicit grant flow
585 func TestCheckCookie(t *testing.T) {
587 req, err := http.NewRequest("GET", "https://auth.secondbit.org", nil)
589 t.Error("Unexpected error creating base request:", err)
591 store := NewMemstore()
592 testContext := Context{
595 session, err := checkCookie(req, testContext)
596 if err != ErrNoSession {
597 t.Errorf("Expected ErrNoSession, got %s", err)
603 Expires: time.Now().Round(time.Millisecond).Add(time.Hour),
605 err = testContext.CreateSession(session)
607 t.Error("Unexpected error persisting session:", err)
609 invalidSession := Session{
613 err = testContext.CreateSession(invalidSession)
615 t.Error("Unexpected error persisting session:", err)
617 result, err := checkCookie(req, testContext)
618 if err != ErrNoSession {
619 t.Errorf("Expected ErrNoSession, got %s", err)
621 req.AddCookie(&http.Cookie{
623 Value: "wrong value",
625 result, err = checkCookie(req, testContext)
626 if err != ErrNoSession {
627 t.Error("Expected ErrNoSession, got", err)
629 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
631 t.Error("Unexpected error creating base request:", err)
633 req.AddCookie(&http.Cookie{
634 Name: "Stillwrongcookie",
637 result, err = checkCookie(req, testContext)
638 if err != ErrNoSession {
639 t.Error("Expected ErrNoSession, got", err)
641 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
643 t.Error("Unexpected error creating base request:", err)
645 req.AddCookie(&http.Cookie{
646 Name: authCookieName,
647 Value: "wrong value",
649 result, err = checkCookie(req, testContext)
650 if err != ErrInvalidSession {
651 t.Error("Expected ErrInvalidSession, got", err)
653 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
655 t.Error("Unexpected error creating base request:", err)
657 req.AddCookie(&http.Cookie{
658 Name: authCookieName,
659 Value: invalidSession.ID,
661 result, err = checkCookie(req, testContext)
662 if err != ErrInvalidSession {
663 t.Error("Expected ErrInvalidSession, got", err)
665 req, err = http.NewRequest("GET", "https://auth.secondbit.org", nil)
667 t.Error("Unexpected error creating base request:", err)
669 req.AddCookie(&http.Cookie{
670 Name: authCookieName,
673 result, err = checkCookie(req, testContext)
675 t.Error("Unexpected error:", err)
677 success, field, expectation, outcome := compareSessions(session, result)
679 t.Errorf(`Expected field %s to be %v, but got %v`, field, expectation, outcome)
683 func TestBuildLoginRedirect(t *testing.T) {
685 req, err := http.NewRequest("GET", "https://client.secondbit.org/my/awesome/path?has=query¶ms=to&screw=this&all=up", nil)
687 t.Error("Unexpected error creating base request:", err)
689 result := buildLoginRedirect(req, Context{})
691 t.Error("Expected empty string as the result, got", result)
693 uri, err := url.Parse("https://auth.secondbit.org/login?query=string&other=param")
695 t.Error("Unexpected error parsing URL:", err)
697 c := Context{loginURI: uri}
698 result = buildLoginRedirect(req, c)
699 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"
700 if result != expectation {
701 t.Errorf(`Expected result string to be "%s", was "%s"`, expectation, result)
705 func TestAuthenticateHelper(t *testing.T) {
707 store := NewMemstore()
714 Passphrase: "f3a4ac4f1d657b2e6e776d24213e39406d50a87a52691a2a78891425af1271d0",
716 Salt: "d82d92cfa8bfb5a08270ebbf39a3710d24b352b937fcc8959ebcb40384cc616b",
719 LockedUntil: time.Time{},
721 PassphraseResetCreated: time.Time{},
722 Created: time.Now().Round(time.Millisecond),
723 LastSeen: time.Time{},
727 Value: "test@example.com",
728 ProfileID: profile.ID,
729 Created: time.Now().Round(time.Millisecond),
730 LastUsed: time.Time{},
732 err := context.SaveProfile(profile)
734 t.Error("Error saving profile:", err)
736 err = context.AddLogin(login)
738 t.Error("Error adding login:", err)
740 response, err := authenticate("test@example.com", "mysecurepassphrase", context)
742 t.Error("Unexpected error:", err)
744 success, field, expectation, result := compareProfiles(profile, response)
746 t.Errorf(`Expected field %s to be "%v", got "%v"`, field, expectation, result)
748 response, err = authenticate("test2@example.com", "mysecurepassphrase", context)
749 if err != ErrIncorrectAuth {
750 t.Error("Expected ErrIncorrectAuth, got", err)
752 response, err = authenticate("test@example.com", "not the right password", context)
753 if err != ErrIncorrectAuth {
754 t.Error("Expected ErrIncorrectAuth, got", err)
757 phrase := "doesn't really matter, the scheme doesn't exist"
758 change := ProfileChange{
759 PassphraseScheme: &scheme,
762 err = context.UpdateProfile(profile.ID, change)
764 t.Error("Unexpected error:", err)
766 response, err = authenticate("test@example.com", "not the right password", context)
767 if err != ErrInvalidPassphraseScheme {
768 t.Error("Expected ErrIncorrectAuth, got", err)
772 func TestGetTokenHandler(t *testing.T) {
774 store := NewMemstore()
782 Secret: "sometimes I feel like I don't know what I'm doing",
783 OwnerID: uuid.NewID(),
784 Name: "A Super Awesome Client!",
785 Logo: "https://logos.secondbit.org/client.png",
786 Website: "https://client.secondbit.org/",
787 Type: "confidential",
789 authCode := AuthorizationCode{
791 Created: time.Now().Round(time.Millisecond),
794 Scopes: []string{"testscope"},
795 RedirectURI: "https://client.secondbit.org/",
797 ProfileID: uuid.NewID(),
799 err := context.SaveAuthorizationCode(authCode)
801 t.Error("Error saving auth code:", err)
803 err = context.SaveClient(client)
805 t.Error("Error saving client:", err)
807 // BUG(paddy): We're only testing that GetTokenHandler returns the right values when we have the right input. But what about when we have the wrong input? We should test for invalid client errors and invalid grant errors to make sure they're triggered.
809 data.Set("grant_type", "authorization_code")
810 data.Set("code", authCode.Code)
811 data.Set("redirect_uri", authCode.RedirectURI)
812 body := bytes.NewBufferString(data.Encode())
813 req, err := http.NewRequest("POST", "https://auth.secondbit.org/", ioutil.NopCloser(body))
815 t.Error("Error constructing request:", err)
817 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
818 req.SetBasicAuth(client.ID.String(), client.Secret)
819 w := httptest.NewRecorder()
820 GetTokenHandler(w, req, context)
821 resp := tokenResponse{}
822 err = json.Unmarshal(w.Body.Bytes(), &resp)
824 t.Error("Error unmarshalling response:", err)
825 t.Error("Response:", w.Body.String())
827 if resp.AccessToken == "" {
828 t.Error("Got blank access token back")
830 if resp.RefreshToken == "" {
831 t.Error("Got blank refresh token back")
833 if resp.TokenType == "" {
834 t.Error("Got blank token type back")
836 if resp.ExpiresIn == 0 {
837 t.Error("Got blank expires in back")
839 tokens, err := context.GetTokensByProfileID(authCode.ProfileID, 1, 0)
841 t.Error("Error retrieving token:", err)
843 if len(tokens) != 1 {
844 t.Fatalf("Expected %d tokens, got %d", 1, len(tokens))
846 if tokens[0].AccessToken != resp.AccessToken {
847 t.Errorf(`Expected access token to be "%s", got "%s"`, tokens[0].AccessToken, resp.AccessToken)
849 if tokens[0].RefreshToken != resp.RefreshToken {
850 t.Errorf(`Expected refresh token to be "%s", got "%s"`, tokens[0].RefreshToken, resp.RefreshToken)
852 if tokens[0].ExpiresIn != resp.ExpiresIn {
853 t.Errorf(`Expected expires in to be %d, got %d`, tokens[0].ExpiresIn, resp.ExpiresIn)
855 if tokens[0].TokenType != resp.TokenType {
856 t.Errorf(`Expected token type to be %s, got %s`, tokens[0].TokenType, resp.TokenType)
858 // BUG(paddy): We need to test for the refresh_token grant type, too.
859 // BUG(paddy): We need to test for the password grant type, too.
860 // BUG(paddy): We need to test for the client_credentials grant type, too.