@@ -321,3 +321,260 @@ func TestSignInPageDirectAccessRedirectsToRoot(t *testing.T) {
321321 t.Fatal(`expected redirect to "/", but was "` + match[1] + `"`)
322322 }
323323}
324+
325+type ValidateTokenTest struct {
326+ opts *Options
327+ proxy *OauthProxy
328+ backend *httptest.Server
329+ response_code int
330+}
331+
332+func NewValidateTokenTest() *ValidateTokenTest {
333+ var vt_test ValidateTokenTest
334+
335+ vt_test.opts = NewOptions()
336+ vt_test.opts.Upstreams = append(vt_test.opts.Upstreams, "unused")
337+ vt_test.opts.CookieSecret = "foobar"
338+ vt_test.opts.ClientID = "bazquux"
339+ vt_test.opts.ClientSecret = "xyzzyplugh"
340+ vt_test.opts.Validate()
341+
342+ vt_test.backend = httptest.NewServer(
343+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
344+ switch r.URL.Path {
345+ case "/oauth/tokeninfo":
346+ w.WriteHeader(vt_test.response_code)
347+ w.Write([]byte("only code matters; contents disregarded"))
348+ default:
349+ w.WriteHeader(500)
350+ w.Write([]byte("unknown URL"))
351+ }
352+ }))
353+ backend_url, _ := url.Parse(vt_test.backend.URL)
354+ vt_test.opts.provider.Data().ValidateUrl = &url.URL{
355+ Scheme: "http",
356+ Host: backend_url.Host,
357+ Path: "/oauth/tokeninfo",
358+ }
359+ vt_test.response_code = 200
360+
361+ vt_test.proxy = NewOauthProxy(vt_test.opts, func(email string) bool {
362+ return true
363+ })
364+ return &vt_test
365+}
366+
367+func (vt_test *ValidateTokenTest) Close() {
368+ vt_test.backend.Close()
369+}
370+
371+func TestValidateTokenEmptyToken(t *testing.T) {
372+ vt_test := NewValidateTokenTest()
373+ defer vt_test.Close()
374+
375+ assert.Equal(t, false, vt_test.proxy.ValidateToken(""))
376+}
377+
378+func TestValidateTokenEmptyValidateUrl(t *testing.T) {
379+ vt_test := NewValidateTokenTest()
380+ defer vt_test.Close()
381+
382+ vt_test.proxy.oauthValidateUrl = nil
383+ assert.Equal(t, false, vt_test.proxy.ValidateToken("foobar"))
384+}
385+
386+func TestValidateTokenRequestNetworkFailure(t *testing.T) {
387+ vt_test := NewValidateTokenTest()
388+ // Close immediately to simulate a network failure
389+ vt_test.Close()
390+
391+ assert.Equal(t, false, vt_test.proxy.ValidateToken("foobar"))
392+}
393+
394+func TestValidateTokenExpiredToken(t *testing.T) {
395+ vt_test := NewValidateTokenTest()
396+ defer vt_test.Close()
397+
398+ vt_test.response_code = 401
399+ assert.Equal(t, false, vt_test.proxy.ValidateToken("foobar"))
400+}
401+
402+func TestValidateTokenValidToken(t *testing.T) {
403+ vt_test := NewValidateTokenTest()
404+ defer vt_test.Close()
405+
406+ assert.Equal(t, true, vt_test.proxy.ValidateToken("foobar"))
407+}
408+
409+type ProcessCookieTest struct {
410+ opts *Options
411+ proxy *OauthProxy
412+ rw *httptest.ResponseRecorder
413+ req *http.Request
414+ backend *httptest.Server
415+ response_code int
416+ validate_user bool
417+}
418+
419+func NewProcessCookieTest() *ProcessCookieTest {
420+ var pc_test ProcessCookieTest
421+
422+ pc_test.opts = NewOptions()
423+ pc_test.opts.Upstreams = append(pc_test.opts.Upstreams, "unused")
424+ pc_test.opts.CookieSecret = "foobar"
425+ pc_test.opts.ClientID = "bazquux"
426+ pc_test.opts.ClientSecret = "xyzzyplugh"
427+ pc_test.opts.CookieSecret = "0123456789abcdef"
428+ // First, set the CookieRefresh option so proxy.AesCipher is created,
429+ // needed to encrypt the access_token.
430+ pc_test.opts.CookieRefresh = time.Duration(24) * time.Hour
431+ pc_test.opts.Validate()
432+
433+ pc_test.proxy = NewOauthProxy(pc_test.opts, func(email string) bool {
434+ return pc_test.validate_user
435+ })
436+
437+ // Now, zero-out proxy.CookieRefresh for the cases that don't involve
438+ // access_token validation.
439+ pc_test.proxy.CookieRefresh = time.Duration(0)
440+ pc_test.rw = httptest.NewRecorder()
441+ pc_test.req, _ = http.NewRequest("GET", "/", strings.NewReader(""))
442+ pc_test.validate_user = true
443+ return &pc_test
444+}
445+
446+func (p *ProcessCookieTest) InstantiateBackend() {
447+ p.backend = httptest.NewServer(
448+ http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
449+ w.WriteHeader(p.response_code)
450+ }))
451+ backend_url, _ := url.Parse(p.backend.URL)
452+ p.proxy.oauthValidateUrl = &url.URL{
453+ Scheme: "http",
454+ Host: backend_url.Host,
455+ Path: "/oauth/tokeninfo",
456+ }
457+ p.response_code = 200
458+}
459+
460+func (p *ProcessCookieTest) Close() {
461+ p.backend.Close()
462+}
463+
464+func (p *ProcessCookieTest) MakeCookie(value, access_token string) *http.Cookie {
465+ cookie_value, _ := buildCookieValue(
466+ value, p.proxy.AesCipher, access_token)
467+ return p.proxy.MakeCookie(p.req, cookie_value, p.opts.CookieExpire)
468+}
469+
470+func (p *ProcessCookieTest) AddCookie(value, access_token string) {
471+ p.req.AddCookie(p.MakeCookie(value, access_token))
472+}
473+
474+func (p *ProcessCookieTest) ProcessCookie() (email, user, access_token string, ok bool) {
475+ return p.proxy.ProcessCookie(p.rw, p.req)
476+}
477+
478+func TestProcessCookie(t *testing.T) {
479+ pc_test := NewProcessCookieTest()
480+
481+ pc_test.AddCookie("michael.bland@gsa.gov", "my_access_token")
482+ email, user, access_token, ok := pc_test.ProcessCookie()
483+ assert.Equal(t, true, ok)
484+ assert.Equal(t, "michael.bland@gsa.gov", email)
485+ assert.Equal(t, "michael.bland", user)
486+ assert.Equal(t, "my_access_token", access_token)
487+}
488+
489+func TestProcessCookieNoCookieError(t *testing.T) {
490+ pc_test := NewProcessCookieTest()
491+ _, _, _, ok := pc_test.ProcessCookie()
492+ assert.Equal(t, false, ok)
493+}
494+
495+func TestProcessCookieFailIfParsingCookieValueFails(t *testing.T) {
496+ pc_test := NewProcessCookieTest()
497+ value, _ := buildCookieValue("michael.bland@gsa.gov",
498+ pc_test.proxy.AesCipher, "my_access_token")
499+ pc_test.req.AddCookie(pc_test.proxy.MakeCookie(
500+ pc_test.req, value+"some bogus bytes",
501+ pc_test.opts.CookieExpire))
502+ _, _, _, ok := pc_test.ProcessCookie()
503+ assert.Equal(t, false, ok)
504+}
505+
506+func TestProcessCookieRefreshNotSet(t *testing.T) {
507+ pc_test := NewProcessCookieTest()
508+ pc_test.InstantiateBackend()
509+ defer pc_test.Close()
510+
511+ pc_test.proxy.CookieExpire = time.Duration(23) * time.Hour
512+ cookie := pc_test.MakeCookie("michael.bland@gsa.gov", "")
513+ pc_test.req.AddCookie(cookie)
514+
515+ _, _, _, ok := pc_test.ProcessCookie()
516+ assert.Equal(t, true, ok)
517+ assert.Equal(t, []string(nil), pc_test.rw.HeaderMap["Set-Cookie"])
518+}
519+
520+func TestProcessCookieRefresh(t *testing.T) {
521+ pc_test := NewProcessCookieTest()
522+ pc_test.InstantiateBackend()
523+ defer pc_test.Close()
524+
525+ pc_test.proxy.CookieExpire = time.Duration(23) * time.Hour
526+ cookie := pc_test.MakeCookie("michael.bland@gsa.gov", "my_access_token")
527+ pc_test.req.AddCookie(cookie)
528+
529+ pc_test.proxy.CookieRefresh = time.Duration(24) * time.Hour
530+ _, _, _, ok := pc_test.ProcessCookie()
531+ assert.Equal(t, true, ok)
532+ assert.NotEqual(t, []string(nil), pc_test.rw.HeaderMap["Set-Cookie"])
533+}
534+
535+func TestProcessCookieRefreshThresholdNotCrossed(t *testing.T) {
536+ pc_test := NewProcessCookieTest()
537+ pc_test.InstantiateBackend()
538+ defer pc_test.Close()
539+
540+ pc_test.proxy.CookieExpire = time.Duration(25) * time.Hour
541+ cookie := pc_test.MakeCookie("michael.bland@gsa.gov", "my_access_token")
542+ pc_test.req.AddCookie(cookie)
543+
544+ pc_test.proxy.CookieRefresh = time.Duration(24) * time.Hour
545+ _, _, _, ok := pc_test.ProcessCookie()
546+ assert.Equal(t, true, ok)
547+ assert.Equal(t, []string(nil), pc_test.rw.HeaderMap["Set-Cookie"])
548+}
549+
550+func TestProcessCookieFailIfRefreshSetAndTokenNoLongerValid(t *testing.T) {
551+ pc_test := NewProcessCookieTest()
552+ pc_test.InstantiateBackend()
553+ defer pc_test.Close()
554+ pc_test.response_code = 401
555+
556+ pc_test.proxy.CookieExpire = time.Duration(23) * time.Hour
557+ cookie := pc_test.MakeCookie("michael.bland@gsa.gov", "my_access_token")
558+ pc_test.req.AddCookie(cookie)
559+
560+ pc_test.proxy.CookieRefresh = time.Duration(24) * time.Hour
561+ _, _, _, ok := pc_test.ProcessCookie()
562+ assert.Equal(t, false, ok)
563+ assert.Equal(t, []string(nil), pc_test.rw.HeaderMap["Set-Cookie"])
564+}
565+
566+func TestProcessCookieFailIfRefreshSetAndUserNoLongerValid(t *testing.T) {
567+ pc_test := NewProcessCookieTest()
568+ pc_test.InstantiateBackend()
569+ defer pc_test.Close()
570+ pc_test.validate_user = false
571+
572+ pc_test.proxy.CookieExpire = time.Duration(23) * time.Hour
573+ cookie := pc_test.MakeCookie("michael.bland@gsa.gov", "my_access_token")
574+ pc_test.req.AddCookie(cookie)
575+
576+ pc_test.proxy.CookieRefresh = time.Duration(24) * time.Hour
577+ _, _, _, ok := pc_test.ProcessCookie()
578+ assert.Equal(t, false, ok)
579+ assert.Equal(t, []string(nil), pc_test.rw.HeaderMap["Set-Cookie"])
580+}