19 "github.com/coreos/go-oidc"
20 "github.com/mbland/hmacauth"
21 "github.com/pusher/oauth2_proxy/pkg/apis/sessions"
22 "github.com/pusher/oauth2_proxy/pkg/logger"
23 "github.com/pusher/oauth2_proxy/pkg/sessions/cookie"
24 "github.com/pusher/oauth2_proxy/providers"
25 "github.com/stretchr/testify/assert"
26 "github.com/stretchr/testify/require"
27 "golang.org/x/net/websocket"
31 logger.SetFlags(logger.Lshortfile)
35type WebSocketOrRestHandler struct {
36 restHandler http.Handler
37 wsHandler http.Handler
40func (h *WebSocketOrRestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
41 if r.Header.Get("Upgrade") == "websocket" {
42 h.wsHandler.ServeHTTP(w, r)
44 h.restHandler.ServeHTTP(w, r)
48func TestWebSocketProxy(t *testing.T) {
49 handler := WebSocketOrRestHandler{
50 restHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
52 hostname, _, _ := net.SplitHostPort(r.Host)
53 w.Write([]byte(hostname))
55 wsHandler: websocket.Handler(func(ws *websocket.Conn) {
58 err := websocket.Message.Receive(ws, &data)
60 t.Fatalf("err %s", err)
63 err = websocket.Message.Send(ws, data)
65 t.Fatalf("err %s", err)
70 backend := httptest.NewServer(&handler)
73 backendURL, _ := url.Parse(backend.URL)
75 options := NewOptions()
76 var auth hmacauth.HmacAuth
77 options.PassHostHeader = true
78 proxyHandler := NewWebSocketOrRestReverseProxy(backendURL, options, auth)
79 frontend := httptest.NewServer(proxyHandler)
80 defer frontend.Close()
82 frontendURL, _ := url.Parse(frontend.URL)
83 frontendWSURL := "ws://" + frontendURL.Host + "/"
85 ws, err := websocket.Dial(frontendWSURL, "", "http://localhost/")
87 t.Fatalf("err %s", err)
89 request := []byte("hello, world!")
90 err = websocket.Message.Send(ws, request)
92 t.Fatalf("err %s", err)
94 var response = make([]byte, 1024)
95 websocket.Message.Receive(ws, &response)
97 t.Fatalf("err %s", err)
99 if g, e := string(request), string(response); g != e {
100 t.Errorf("got body %q; expected %q", g, e)
103 getReq, _ := http.NewRequest("GET", frontend.URL, nil)
104 res, _ := http.DefaultClient.Do(getReq)
105 bodyBytes, _ := ioutil.ReadAll(res.Body)
106 backendHostname, _, _ := net.SplitHostPort(backendURL.Host)
107 if g, e := string(bodyBytes), backendHostname; g != e {
108 t.Errorf("got body %q; expected %q", g, e)
112func TestNewReverseProxy(t *testing.T) {
113 backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
115 hostname, _, _ := net.SplitHostPort(r.Host)
116 w.Write([]byte(hostname))
118 defer backend.Close()
120 backendURL, _ := url.Parse(backend.URL)
121 backendHostname, backendPort, _ := net.SplitHostPort(backendURL.Host)
122 backendHost := net.JoinHostPort(backendHostname, backendPort)
123 proxyURL, _ := url.Parse(backendURL.Scheme + "://" + backendHost + "/")
125 proxyHandler := NewReverseProxy(proxyURL, &Options{FlushInterval: time.Second})
126 setProxyUpstreamHostHeader(proxyHandler, proxyURL)
127 frontend := httptest.NewServer(proxyHandler)
128 defer frontend.Close()
130 getReq, _ := http.NewRequest("GET", frontend.URL, nil)
131 res, _ := http.DefaultClient.Do(getReq)
132 bodyBytes, _ := ioutil.ReadAll(res.Body)
133 if g, e := string(bodyBytes), backendHostname; g != e {
134 t.Errorf("got body %q; expected %q", g, e)
138func TestEncodedSlashes(t *testing.T) {
140 backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
144 defer backend.Close()
146 b, _ := url.Parse(backend.URL)
147 proxyHandler := NewReverseProxy(b, &Options{FlushInterval: time.Second})
148 setProxyDirector(proxyHandler)
149 frontend := httptest.NewServer(proxyHandler)
150 defer frontend.Close()
152 f, _ := url.Parse(frontend.URL)
153 encodedPath := "/a%2Fb/?c=1"
154 getReq := &http.Request{URL: &url.URL{Scheme: "http", Host: f.Host, Opaque: encodedPath}}
155 _, err := http.DefaultClient.Do(getReq)
157 t.Fatalf("err %s", err)
159 if seen != encodedPath {
160 t.Errorf("got bad request %q expected %q", seen, encodedPath)
164func TestRobotsTxt(t *testing.T) {
166 opts.ClientID = "asdlkjx"
167 opts.ClientSecret = "alkgks"
168 opts.CookieSecret = "asdkugkj"
171 proxy := NewOAuthProxy(opts, func(string) bool { return true })
172 rw := httptest.NewRecorder()
173 req, _ := http.NewRequest("GET", "/robots.txt", nil)
174 proxy.ServeHTTP(rw, req)
175 assert.Equal(t, 200, rw.Code)
176 assert.Equal(t, "User-agent: *\nDisallow: /", rw.Body.String())
179func TestIsValidRedirect(t *testing.T) {
181 opts.ClientID = "skdlfj"
182 opts.ClientSecret = "fgkdsgj"
183 opts.CookieSecret = "ljgiogbj"
184 // Should match domains that are exactly foo.bar and any subdomain of bar.foo
185 opts.WhitelistDomains = []string{
189 ".sub.port.bar:8080",
191 ".sub.anyport.bar:*",
195 proxy := NewOAuthProxy(opts, func(string) bool { return true })
197 testCases := []struct {
198 Desc, Redirect string
204 ExpectedResult: false,
208 Redirect: "/redirect",
209 ExpectedResult: true,
213 Redirect: "//redirect",
214 ExpectedResult: false,
218 Redirect: "http://foo.bar/redirect",
219 ExpectedResult: true,
223 Redirect: "https://foo.bar/redirect",
224 ExpectedResult: true,
227 Desc: "invalidHTTPSubdomain",
228 Redirect: "http://baz.foo.bar/redirect",
229 ExpectedResult: false,
232 Desc: "invalidHTTPSSubdomain",
233 Redirect: "https://baz.foo.bar/redirect",
234 ExpectedResult: false,
237 Desc: "validHTTPSubdomain",
238 Redirect: "http://baz.bar.foo/redirect",
239 ExpectedResult: true,
242 Desc: "validHTTPSSubdomain",
243 Redirect: "https://baz.bar.foo/redirect",
244 ExpectedResult: true,
247 Desc: "validHTTPDomain",
248 Redirect: "http://bar.foo/redirect",
249 ExpectedResult: true,
252 Desc: "invalidHTTP1",
253 Redirect: "http://foo.bar.evil.corp/redirect",
254 ExpectedResult: false,
257 Desc: "invalidHTTPS1",
258 Redirect: "https://foo.bar.evil.corp/redirect",
259 ExpectedResult: false,
262 Desc: "invalidHTTP2",
263 Redirect: "http://evil.corp/redirect?rd=foo.bar",
264 ExpectedResult: false,
267 Desc: "invalidHTTPS2",
268 Redirect: "https://evil.corp/redirect?rd=foo.bar",
269 ExpectedResult: false,
273 Redirect: "https://evil.corp:3838/redirect",
274 ExpectedResult: false,
277 Desc: "invalidEmptyPort",
278 Redirect: "http://foo.bar:3838/redirect",
279 ExpectedResult: false,
282 Desc: "invalidEmptyPortSubdomain",
283 Redirect: "http://baz.bar.foo:3838/redirect",
284 ExpectedResult: false,
287 Desc: "validSpecificPort",
288 Redirect: "http://port.bar:8080/redirect",
289 ExpectedResult: true,
292 Desc: "invalidSpecificPort",
293 Redirect: "http://port.bar:3838/redirect",
294 ExpectedResult: false,
297 Desc: "validSpecificPortSubdomain",
298 Redirect: "http://foo.sub.port.bar:8080/redirect",
299 ExpectedResult: true,
302 Desc: "invalidSpecificPortSubdomain",
303 Redirect: "http://foo.sub.port.bar:3838/redirect",
304 ExpectedResult: false,
307 Desc: "validAnyPort1",
308 Redirect: "http://anyport.bar:8080/redirect",
309 ExpectedResult: true,
312 Desc: "validAnyPort2",
313 Redirect: "http://anyport.bar:8081/redirect",
314 ExpectedResult: true,
317 Desc: "validAnyPortSubdomain1",
318 Redirect: "http://a.sub.anyport.bar:8080/redirect",
319 ExpectedResult: true,
322 Desc: "validAnyPortSubdomain2",
323 Redirect: "http://a.sub.anyport.bar:8081/redirect",
324 ExpectedResult: true,
327 Desc: "openRedirect1",
328 Redirect: "/\\evil.com",
329 ExpectedResult: false,
332 Desc: "openRedirectSpace1",
333 Redirect: "/ /evil.com",
334 ExpectedResult: false,
337 Desc: "openRedirectSpace2",
338 Redirect: "/ \\evil.com",
339 ExpectedResult: false,
342 Desc: "openRedirectTab1",
343 Redirect: "/\t/evil.com",
344 ExpectedResult: false,
347 Desc: "openRedirectTab2",
348 Redirect: "/\t\\evil.com",
349 ExpectedResult: false,
352 Desc: "openRedirectVerticalTab1",
353 Redirect: "/\v/evil.com",
354 ExpectedResult: false,
357 Desc: "openRedirectVerticalTab2",
358 Redirect: "/\v\\evil.com",
359 ExpectedResult: false,
362 Desc: "openRedirectNewLine1",
363 Redirect: "/\n/evil.com",
364 ExpectedResult: false,
367 Desc: "openRedirectNewLine2",
368 Redirect: "/\n\\evil.com",
369 ExpectedResult: false,
372 Desc: "openRedirectCarriageReturn1",
373 Redirect: "/\r/evil.com",
374 ExpectedResult: false,
377 Desc: "openRedirectCarriageReturn2",
378 Redirect: "/\r\\evil.com",
379 ExpectedResult: false,
383 for _, tc := range testCases {
384 t.Run(tc.Desc, func(t *testing.T) {
385 result := proxy.IsValidRedirect(tc.Redirect)
387 if result != tc.ExpectedResult {
388 t.Errorf("expected %t got %t", tc.ExpectedResult, result)
394type TestProvider struct {
395 *providers.ProviderData
398 GroupValidator func(string) bool
401func NewTestProvider(providerURL *url.URL, emailAddress string) *TestProvider {
402 return &TestProvider{
403 ProviderData: &providers.ProviderData{
404 ProviderName: "Test Provider",
407 Host: providerURL.Host,
408 Path: "/oauth/authorize",
412 Host: providerURL.Host,
413 Path: "/oauth/token",
415 ProfileURL: &url.URL{
417 Host: providerURL.Host,
418 Path: "/api/v1/profile",
420 Scope: "profile.email",
422 EmailAddress: emailAddress,
423 GroupValidator: func(s string) bool {
429func (tp *TestProvider) GetEmailAddress(session *sessions.SessionState) (string, error) {
430 return tp.EmailAddress, nil
433func (tp *TestProvider) ValidateSessionState(session *sessions.SessionState) bool {
437func TestBasicAuthPassword(t *testing.T) {
438 providerServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
439 logger.Printf("%#v", r)
443 payload = `{"access_token": "my_auth_token"}`
445 payload = r.Header.Get("Authorization")
447 payload = "No Authorization header found."
451 w.Write([]byte(payload))
454 opts.Upstreams = append(opts.Upstreams, providerServer.URL)
455 // The CookieSecret must be 32 bytes in order to create the AES
457 opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
458 opts.ClientID = "dlgkj"
459 opts.ClientSecret = "alkgret"
460 opts.CookieSecure = false
461 opts.PassBasicAuth = true
462 opts.PassUserHeaders = true
463 opts.PreferEmailToUser = true
464 opts.BasicAuthPassword = "This is a secure password"
467 providerURL, _ := url.Parse(providerServer.URL)
468 const emailAddress = "john.doe@example.com"
470 opts.provider = NewTestProvider(providerURL, emailAddress)
471 proxy := NewOAuthProxy(opts, func(email string) bool {
472 return email == emailAddress
475 rw := httptest.NewRecorder()
476 req, _ := http.NewRequest("GET", "/oauth2/callback?code=callback_code&state=nonce:",
477 strings.NewReader(""))
478 req.AddCookie(proxy.MakeCSRFCookie(req, "nonce", proxy.CookieExpire, time.Now()))
479 proxy.ServeHTTP(rw, req)
481 t.Fatalf("expected 3xx got %d", rw.Code)
483 cookie := rw.HeaderMap["Set-Cookie"][1]
485 cookieName := proxy.CookieName
487 keyPrefix := cookieName + "="
489 for _, field := range strings.Split(cookie, "; ") {
490 value = strings.TrimPrefix(field, keyPrefix)
498 req, _ = http.NewRequest("GET", "/", strings.NewReader(""))
499 req.AddCookie(&http.Cookie{
503 Expires: time.Now().Add(time.Duration(24)),
506 req.AddCookie(proxy.MakeCSRFCookie(req, "nonce", proxy.CookieExpire, time.Now()))
508 rw = httptest.NewRecorder()
509 proxy.ServeHTTP(rw, req)
511 // The username in the basic auth credentials is expected to be equal to the email address from the
512 // auth response, so we use the same variable here.
513 expectedHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(emailAddress+":"+opts.BasicAuthPassword))
514 assert.Equal(t, expectedHeader, rw.Body.String())
515 providerServer.Close()
518func TestBasicAuthWithEmail(t *testing.T) {
520 opts.PassBasicAuth = true
521 opts.PassUserHeaders = false
522 opts.PreferEmailToUser = false
523 opts.BasicAuthPassword = "This is a secure password"
526 const emailAddress = "john.doe@example.com"
527 const userName = "9fcab5c9b889a557"
529 // The username in the basic auth credentials is expected to be equal to the email address from the
530 expectedEmailHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(emailAddress+":"+opts.BasicAuthPassword))
531 expectedUserHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(userName+":"+opts.BasicAuthPassword))
533 session := &sessions.SessionState{
536 AccessToken: "oauth_token",
537 CreatedAt: time.Now(),
540 rw := httptest.NewRecorder()
541 req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase0", nil)
542 proxy := NewOAuthProxy(opts, func(email string) bool {
543 return email == emailAddress
545 proxy.addHeadersForProxying(rw, req, session)
546 assert.Equal(t, expectedUserHeader, req.Header["Authorization"][0])
547 assert.Equal(t, userName, req.Header["X-Forwarded-User"][0])
550 opts.PreferEmailToUser = true
552 rw := httptest.NewRecorder()
553 req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase1", nil)
555 proxy := NewOAuthProxy(opts, func(email string) bool {
556 return email == emailAddress
558 proxy.addHeadersForProxying(rw, req, session)
559 assert.Equal(t, expectedEmailHeader, req.Header["Authorization"][0])
560 assert.Equal(t, emailAddress, req.Header["X-Forwarded-User"][0])
564func TestPassUserHeadersWithEmail(t *testing.T) {
566 opts.PassBasicAuth = false
567 opts.PassUserHeaders = true
568 opts.PreferEmailToUser = false
571 const emailAddress = "john.doe@example.com"
572 const userName = "9fcab5c9b889a557"
574 session := &sessions.SessionState{
577 AccessToken: "oauth_token",
578 CreatedAt: time.Now(),
581 rw := httptest.NewRecorder()
582 req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase0", nil)
583 proxy := NewOAuthProxy(opts, func(email string) bool {
584 return email == emailAddress
586 proxy.addHeadersForProxying(rw, req, session)
587 assert.Equal(t, userName, req.Header["X-Forwarded-User"][0])
590 opts.PreferEmailToUser = true
592 rw := httptest.NewRecorder()
593 req, _ := http.NewRequest("GET", opts.ProxyPrefix+"/testCase1", nil)
595 proxy := NewOAuthProxy(opts, func(email string) bool {
596 return email == emailAddress
598 proxy.addHeadersForProxying(rw, req, session)
599 assert.Equal(t, emailAddress, req.Header["X-Forwarded-User"][0])
603type PassAccessTokenTest struct {
604 providerServer *httptest.Server
609type PassAccessTokenTestOptions struct {
614func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTest {
615 t := &PassAccessTokenTest{}
617 t.providerServer = httptest.NewServer(
618 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
622 payload = `{"access_token": "my_auth_token"}`
624 payload = r.Header.Get("X-Forwarded-Access-Token")
626 payload = "No access token found."
630 w.Write([]byte(payload))
633 t.opts = NewOptions()
634 t.opts.Upstreams = append(t.opts.Upstreams, t.providerServer.URL)
635 if opts.ProxyUpstream != "" {
636 t.opts.Upstreams = append(t.opts.Upstreams, opts.ProxyUpstream)
638 // The CookieSecret must be 32 bytes in order to create the AES
640 t.opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
641 t.opts.ClientID = "slgkj"
642 t.opts.ClientSecret = "gfjgojl"
643 t.opts.CookieSecure = false
644 t.opts.PassAccessToken = opts.PassAccessToken
647 providerURL, _ := url.Parse(t.providerServer.URL)
648 const emailAddress = "michael.bland@gsa.gov"
650 t.opts.provider = NewTestProvider(providerURL, emailAddress)
651 t.proxy = NewOAuthProxy(t.opts, func(email string) bool {
652 return email == emailAddress
657func (patTest *PassAccessTokenTest) Close() {
658 patTest.providerServer.Close()
661func (patTest *PassAccessTokenTest) getCallbackEndpoint() (httpCode int,
663 rw := httptest.NewRecorder()
664 req, err := http.NewRequest("GET", "/oauth2/callback?code=callback_code&state=nonce:",
665 strings.NewReader(""))
669 req.AddCookie(patTest.proxy.MakeCSRFCookie(req, "nonce", time.Hour, time.Now()))
670 patTest.proxy.ServeHTTP(rw, req)
671 return rw.Code, rw.HeaderMap["Set-Cookie"][1]
674// getEndpointWithCookie makes a requests againt the oauthproxy with passed requestPath
675// and cookie and returns body and status code.
676func (patTest *PassAccessTokenTest) getEndpointWithCookie(cookie string, endpoint string) (httpCode int, accessToken string) {
677 cookieName := patTest.proxy.CookieName
679 keyPrefix := cookieName + "="
681 for _, field := range strings.Split(cookie, "; ") {
682 value = strings.TrimPrefix(field, keyPrefix)
693 req, err := http.NewRequest("GET", endpoint, strings.NewReader(""))
697 req.AddCookie(&http.Cookie{
701 Expires: time.Now().Add(time.Duration(24)),
705 rw := httptest.NewRecorder()
706 patTest.proxy.ServeHTTP(rw, req)
707 return rw.Code, rw.Body.String()
710func TestForwardAccessTokenUpstream(t *testing.T) {
711 patTest := NewPassAccessTokenTest(PassAccessTokenTestOptions{
712 PassAccessToken: true,
714 defer patTest.Close()
716 // A successful validation will redirect and set the auth cookie.
717 code, cookie := patTest.getCallbackEndpoint()
719 t.Fatalf("expected 302; got %d", code)
721 assert.NotEqual(t, nil, cookie)
723 // Now we make a regular request; the access_token from the cookie is
724 // forwarded as the "X-Forwarded-Access-Token" header. The token is
725 // read by the test provider server and written in the response body.
726 code, payload := patTest.getEndpointWithCookie(cookie, "/")
728 t.Fatalf("expected 200; got %d", code)
730 assert.Equal(t, "my_auth_token", payload)
733func TestStaticProxyUpstream(t *testing.T) {
734 patTest := NewPassAccessTokenTest(PassAccessTokenTestOptions{
735 PassAccessToken: true,
736 ProxyUpstream: "static://200/static-proxy",
739 defer patTest.Close()
741 // A successful validation will redirect and set the auth cookie.
742 code, cookie := patTest.getCallbackEndpoint()
744 t.Fatalf("expected 302; got %d", code)
746 assert.NotEqual(t, nil, cookie)
748 // Now we make a regular request againts the upstream proxy; And validate
749 // the returned status code through the static proxy.
750 code, payload := patTest.getEndpointWithCookie(cookie, "/static-proxy")
752 t.Fatalf("expected 200; got %d", code)
754 assert.Equal(t, "Authenticated", payload)
757func TestDoNotForwardAccessTokenUpstream(t *testing.T) {
758 patTest := NewPassAccessTokenTest(PassAccessTokenTestOptions{
759 PassAccessToken: false,
761 defer patTest.Close()
763 // A successful validation will redirect and set the auth cookie.
764 code, cookie := patTest.getCallbackEndpoint()
766 t.Fatalf("expected 302; got %d", code)
768 assert.NotEqual(t, nil, cookie)
770 // Now we make a regular request, but the access token header should
772 code, payload := patTest.getEndpointWithCookie(cookie, "/")
774 t.Fatalf("expected 200; got %d", code)
776 assert.Equal(t, "No access token found.", payload)
779type SignInPageTest struct {
782 signInRegexp *regexp.Regexp
783 signInProviderRegexp *regexp.Regexp
786const signInRedirectPattern = `<input type="hidden" name="rd" value="(.*)">`
787const signInSkipProvider = `>Found<`
789func NewSignInPageTest(skipProvider bool) *SignInPageTest {
790 var sipTest SignInPageTest
792 sipTest.opts = NewOptions()
793 sipTest.opts.CookieSecret = "adklsj2"
794 sipTest.opts.ClientID = "lkdgj"
795 sipTest.opts.ClientSecret = "sgiufgoi"
796 sipTest.opts.SkipProviderButton = skipProvider
797 sipTest.opts.Validate()
799 sipTest.proxy = NewOAuthProxy(sipTest.opts, func(email string) bool {
802 sipTest.signInRegexp = regexp.MustCompile(signInRedirectPattern)
803 sipTest.signInProviderRegexp = regexp.MustCompile(signInSkipProvider)
808func (sipTest *SignInPageTest) GetEndpoint(endpoint string) (int, string) {
809 rw := httptest.NewRecorder()
810 req, _ := http.NewRequest("GET", endpoint, strings.NewReader(""))
811 sipTest.proxy.ServeHTTP(rw, req)
812 return rw.Code, rw.Body.String()
815func TestSignInPageIncludesTargetRedirect(t *testing.T) {
816 sipTest := NewSignInPageTest(false)
817 const endpoint = "/some/random/endpoint"
819 code, body := sipTest.GetEndpoint(endpoint)
820 assert.Equal(t, 403, code)
822 match := sipTest.signInRegexp.FindStringSubmatch(body)
824 t.Fatal("Did not find pattern in body: " +
825 signInRedirectPattern + "\nBody:\n" + body)
827 if match[1] != endpoint {
828 t.Fatal(`expected redirect to "` + endpoint +
829 `", but was "` + match[1] + `"`)
833func TestSignInPageDirectAccessRedirectsToRoot(t *testing.T) {
834 sipTest := NewSignInPageTest(false)
835 code, body := sipTest.GetEndpoint("/oauth2/sign_in")
836 assert.Equal(t, 200, code)
838 match := sipTest.signInRegexp.FindStringSubmatch(body)
840 t.Fatal("Did not find pattern in body: " +
841 signInRedirectPattern + "\nBody:\n" + body)
844 t.Fatal(`expected redirect to "/", but was "` + match[1] + `"`)
848func TestSignInPageSkipProvider(t *testing.T) {
849 sipTest := NewSignInPageTest(true)
850 const endpoint = "/some/random/endpoint"
852 code, body := sipTest.GetEndpoint(endpoint)
853 assert.Equal(t, 302, code)
855 match := sipTest.signInProviderRegexp.FindStringSubmatch(body)
857 t.Fatal("Did not find pattern in body: " +
858 signInSkipProvider + "\nBody:\n" + body)
862func TestSignInPageSkipProviderDirect(t *testing.T) {
863 sipTest := NewSignInPageTest(true)
864 const endpoint = "/sign_in"
866 code, body := sipTest.GetEndpoint(endpoint)
867 assert.Equal(t, 302, code)
869 match := sipTest.signInProviderRegexp.FindStringSubmatch(body)
871 t.Fatal("Did not find pattern in body: " +
872 signInSkipProvider + "\nBody:\n" + body)
876type ProcessCookieTest struct {
879 rw *httptest.ResponseRecorder
881 provider TestProvider
886type ProcessCookieTestOpts struct {
887 providerValidateCookieResponse bool
890type OptionsModifier func(*Options)
892func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifier) *ProcessCookieTest {
893 var pcTest ProcessCookieTest
895 pcTest.opts = NewOptions()
896 for _, modifier := range modifiers {
897 modifier(pcTest.opts)
899 pcTest.opts.ClientID = "asdfljk"
900 pcTest.opts.ClientSecret = "lkjfdsig"
901 pcTest.opts.CookieSecret = "0123456789abcdefabcd"
902 // First, set the CookieRefresh option so proxy.AesCipher is created,
903 // needed to encrypt the access_token.
904 pcTest.opts.CookieRefresh = time.Hour
905 pcTest.opts.Validate()
907 pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
908 return pcTest.validateUser
910 pcTest.proxy.provider = &TestProvider{
911 ValidToken: opts.providerValidateCookieResponse,
914 // Now, zero-out proxy.CookieRefresh for the cases that don't involve
915 // access_token validation.
916 pcTest.proxy.CookieRefresh = time.Duration(0)
917 pcTest.rw = httptest.NewRecorder()
918 pcTest.req, _ = http.NewRequest("GET", "/", strings.NewReader(""))
919 pcTest.validateUser = true
923func NewProcessCookieTestWithDefaults() *ProcessCookieTest {
924 return NewProcessCookieTest(ProcessCookieTestOpts{
925 providerValidateCookieResponse: true,
929func NewProcessCookieTestWithOptionsModifiers(modifiers ...OptionsModifier) *ProcessCookieTest {
930 return NewProcessCookieTest(ProcessCookieTestOpts{
931 providerValidateCookieResponse: true,
935func (p *ProcessCookieTest) SaveSession(s *sessions.SessionState) error {
936 err := p.proxy.SaveSession(p.rw, p.req, s)
940 for _, cookie := range p.rw.Result().Cookies() {
941 p.req.AddCookie(cookie)
946func (p *ProcessCookieTest) LoadCookiedSession() (*sessions.SessionState, error) {
947 return p.proxy.LoadCookiedSession(p.req)
950func TestLoadCookiedSession(t *testing.T) {
951 pcTest := NewProcessCookieTestWithDefaults()
953 startSession := &sessions.SessionState{Email: "john.doe@example.com", AccessToken: "my_access_token", CreatedAt: time.Now()}
954 pcTest.SaveSession(startSession)
956 session, err := pcTest.LoadCookiedSession()
957 assert.Equal(t, nil, err)
958 assert.Equal(t, startSession.Email, session.Email)
959 assert.Equal(t, "john.doe@example.com", session.User)
960 assert.Equal(t, startSession.AccessToken, session.AccessToken)
963func TestProcessCookieNoCookieError(t *testing.T) {
964 pcTest := NewProcessCookieTestWithDefaults()
966 session, err := pcTest.LoadCookiedSession()
967 assert.Equal(t, "Cookie \"_oauth2_proxy\" not present", err.Error())
969 t.Errorf("expected nil session. got %#v", session)
973func TestProcessCookieRefreshNotSet(t *testing.T) {
974 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
975 opts.CookieExpire = time.Duration(23) * time.Hour
977 reference := time.Now().Add(time.Duration(-2) * time.Hour)
979 startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
980 pcTest.SaveSession(startSession)
982 session, err := pcTest.LoadCookiedSession()
983 assert.Equal(t, nil, err)
984 if session.Age() < time.Duration(-2)*time.Hour {
985 t.Errorf("cookie too young %v", session.Age())
987 assert.Equal(t, startSession.Email, session.Email)
990func TestProcessCookieFailIfCookieExpired(t *testing.T) {
991 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
992 opts.CookieExpire = time.Duration(24) * time.Hour
994 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
995 startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
996 pcTest.SaveSession(startSession)
998 session, err := pcTest.LoadCookiedSession()
999 assert.NotEqual(t, nil, err)
1001 t.Errorf("expected nil session %#v", session)
1005func TestProcessCookieFailIfRefreshSetAndCookieExpired(t *testing.T) {
1006 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
1007 opts.CookieExpire = time.Duration(24) * time.Hour
1009 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
1010 startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
1011 pcTest.SaveSession(startSession)
1013 pcTest.proxy.CookieRefresh = time.Hour
1014 session, err := pcTest.LoadCookiedSession()
1015 assert.NotEqual(t, nil, err)
1017 t.Errorf("expected nil session %#v", session)
1021func NewUserInfoEndpointTest() *ProcessCookieTest {
1022 pcTest := NewProcessCookieTestWithDefaults()
1023 pcTest.req, _ = http.NewRequest("GET",
1024 pcTest.opts.ProxyPrefix+"/userinfo", nil)
1028func TestUserInfoEndpointAccepted(t *testing.T) {
1029 test := NewUserInfoEndpointTest()
1030 startSession := &sessions.SessionState{
1031 Email: "john.doe@example.com", AccessToken: "my_access_token"}
1032 test.SaveSession(startSession)
1034 test.proxy.ServeHTTP(test.rw, test.req)
1035 assert.Equal(t, http.StatusOK, test.rw.Code)
1036 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
1037 assert.Equal(t, "{\"email\":\"john.doe@example.com\"}\n", string(bodyBytes))
1040func TestUserInfoEndpointUnauthorizedOnNoCookieSetError(t *testing.T) {
1041 test := NewUserInfoEndpointTest()
1043 test.proxy.ServeHTTP(test.rw, test.req)
1044 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
1047func NewAuthOnlyEndpointTest(modifiers ...OptionsModifier) *ProcessCookieTest {
1048 pcTest := NewProcessCookieTestWithOptionsModifiers(modifiers...)
1049 pcTest.req, _ = http.NewRequest("GET",
1050 pcTest.opts.ProxyPrefix+"/auth", nil)
1054func TestAuthOnlyEndpointAccepted(t *testing.T) {
1055 test := NewAuthOnlyEndpointTest()
1056 startSession := &sessions.SessionState{
1057 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: time.Now()}
1058 test.SaveSession(startSession)
1060 test.proxy.ServeHTTP(test.rw, test.req)
1061 assert.Equal(t, http.StatusAccepted, test.rw.Code)
1062 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
1063 assert.Equal(t, "", string(bodyBytes))
1066func TestAuthOnlyEndpointUnauthorizedOnNoCookieSetError(t *testing.T) {
1067 test := NewAuthOnlyEndpointTest()
1069 test.proxy.ServeHTTP(test.rw, test.req)
1070 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
1071 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
1072 assert.Equal(t, "unauthorized request\n", string(bodyBytes))
1075func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
1076 test := NewAuthOnlyEndpointTest(func(opts *Options) {
1077 opts.CookieExpire = time.Duration(24) * time.Hour
1079 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
1080 startSession := &sessions.SessionState{
1081 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
1082 test.SaveSession(startSession)
1084 test.proxy.ServeHTTP(test.rw, test.req)
1085 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
1086 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
1087 assert.Equal(t, "unauthorized request\n", string(bodyBytes))
1090func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure(t *testing.T) {
1091 test := NewAuthOnlyEndpointTest()
1092 startSession := &sessions.SessionState{
1093 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: time.Now()}
1094 test.SaveSession(startSession)
1095 test.validateUser = false
1097 test.proxy.ServeHTTP(test.rw, test.req)
1098 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
1099 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
1100 assert.Equal(t, "unauthorized request\n", string(bodyBytes))
1103func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
1104 var pcTest ProcessCookieTest
1106 pcTest.opts = NewOptions()
1107 pcTest.opts.SetXAuthRequest = true
1108 pcTest.opts.Validate()
1110 pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
1111 return pcTest.validateUser
1113 pcTest.proxy.provider = &TestProvider{
1117 pcTest.validateUser = true
1119 pcTest.rw = httptest.NewRecorder()
1120 pcTest.req, _ = http.NewRequest("GET",
1121 pcTest.opts.ProxyPrefix+"/auth", nil)
1123 startSession := &sessions.SessionState{
1124 User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token", CreatedAt: time.Now()}
1125 pcTest.SaveSession(startSession)
1127 pcTest.proxy.ServeHTTP(pcTest.rw, pcTest.req)
1128 assert.Equal(t, http.StatusAccepted, pcTest.rw.Code)
1129 assert.Equal(t, "oauth_user", pcTest.rw.HeaderMap["X-Auth-Request-User"][0])
1130 assert.Equal(t, "oauth_user@example.com", pcTest.rw.HeaderMap["X-Auth-Request-Email"][0])
1133func TestAuthSkippedForPreflightRequests(t *testing.T) {
1134 upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1136 w.Write([]byte("response"))
1138 defer upstream.Close()
1140 opts := NewOptions()
1141 opts.Upstreams = append(opts.Upstreams, upstream.URL)
1142 opts.ClientID = "aljsal"
1143 opts.ClientSecret = "jglkfsdgj"
1144 opts.CookieSecret = "dkfjgdls"
1145 opts.SkipAuthPreflight = true
1148 upstreamURL, _ := url.Parse(upstream.URL)
1149 opts.provider = NewTestProvider(upstreamURL, "")
1151 proxy := NewOAuthProxy(opts, func(string) bool { return false })
1152 rw := httptest.NewRecorder()
1153 req, _ := http.NewRequest("OPTIONS", "/preflight-request", nil)
1154 proxy.ServeHTTP(rw, req)
1156 assert.Equal(t, 200, rw.Code)
1157 assert.Equal(t, "response", rw.Body.String())
1160type SignatureAuthenticator struct {
1161 auth hmacauth.HmacAuth
1164func (v *SignatureAuthenticator) Authenticate(w http.ResponseWriter, r *http.Request) {
1165 result, headerSig, computedSig := v.auth.AuthenticateRequest(r)
1166 if result == hmacauth.ResultNoSignature {
1167 w.Write([]byte("no signature received"))
1168 } else if result == hmacauth.ResultMatch {
1169 w.Write([]byte("signatures match"))
1170 } else if result == hmacauth.ResultMismatch {
1171 w.Write([]byte("signatures do not match:" +
1172 "\n received: " + headerSig +
1173 "\n computed: " + computedSig))
1175 panic("Unknown result value: " + result.String())
1179type SignatureTest struct {
1181 upstream *httptest.Server
1183 provider *httptest.Server
1185 rw *httptest.ResponseRecorder
1186 authenticator *SignatureAuthenticator
1189func NewSignatureTest() *SignatureTest {
1190 opts := NewOptions()
1191 opts.CookieSecret = "cookie secret"
1192 opts.ClientID = "client ID"
1193 opts.ClientSecret = "client secret"
1194 opts.EmailDomains = []string{"acm.org"}
1196 authenticator := &SignatureAuthenticator{}
1197 upstream := httptest.NewServer(
1198 http.HandlerFunc(authenticator.Authenticate))
1199 upstreamURL, _ := url.Parse(upstream.URL)
1200 opts.Upstreams = append(opts.Upstreams, upstream.URL)
1202 providerHandler := func(w http.ResponseWriter, r *http.Request) {
1203 w.Write([]byte(`{"access_token": "my_auth_token"}`))
1205 provider := httptest.NewServer(http.HandlerFunc(providerHandler))
1206 providerURL, _ := url.Parse(provider.URL)
1207 opts.provider = NewTestProvider(providerURL, "mbland@acm.org")
1209 return &SignatureTest{
1215 httptest.NewRecorder(),
1220func (st *SignatureTest) Close() {
1225// fakeNetConn simulates an http.Request.Body buffer that will be consumed
1226// when it is read by the hmacauth.HmacAuth if not handled properly. See:
1227// https://github.com/18F/hmacauth/pull/4
1228type fakeNetConn struct {
1232func (fnc *fakeNetConn) Read(p []byte) (n int, err error) {
1233 if bodyLen := len(fnc.reqBody); bodyLen != 0 {
1234 copy(p, fnc.reqBody)
1236 return bodyLen, io.EOF
1241func (st *SignatureTest) MakeRequestWithExpectedKey(method, body, key string) {
1242 err := st.opts.Validate()
1246 proxy := NewOAuthProxy(st.opts, func(email string) bool { return true })
1248 var bodyBuf io.ReadCloser
1250 bodyBuf = ioutil.NopCloser(&fakeNetConn{reqBody: body})
1252 req := httptest.NewRequest(method, "/foo/bar", bodyBuf)
1253 req.Header = st.header
1255 state := &sessions.SessionState{
1256 Email: "mbland@acm.org", AccessToken: "my_access_token"}
1257 err = proxy.SaveSession(st.rw, req, state)
1261 for _, c := range st.rw.Result().Cookies() {
1264 // This is used by the upstream to validate the signature.
1265 st.authenticator.auth = hmacauth.NewHmacAuth(
1266 crypto.SHA1, []byte(key), SignatureHeader, SignatureHeaders)
1267 proxy.ServeHTTP(st.rw, req)
1270func TestNoRequestSignature(t *testing.T) {
1271 st := NewSignatureTest()
1273 st.MakeRequestWithExpectedKey("GET", "", "")
1274 assert.Equal(t, 200, st.rw.Code)
1275 assert.Equal(t, st.rw.Body.String(), "no signature received")
1278func TestRequestSignatureGetRequest(t *testing.T) {
1279 st := NewSignatureTest()
1281 st.opts.SignatureKey = "sha1:7d9e1aa87a5954e6f9fc59266b3af9d7c35fda2d"
1282 st.MakeRequestWithExpectedKey("GET", "", "7d9e1aa87a5954e6f9fc59266b3af9d7c35fda2d")
1283 assert.Equal(t, 200, st.rw.Code)
1284 assert.Equal(t, st.rw.Body.String(), "signatures match")
1287func TestRequestSignaturePostRequest(t *testing.T) {
1288 st := NewSignatureTest()
1290 st.opts.SignatureKey = "sha1:d90df39e2d19282840252612dd7c81421a372f61"
1291 payload := `{ "hello": "world!" }`
1292 st.MakeRequestWithExpectedKey("POST", payload, "d90df39e2d19282840252612dd7c81421a372f61")
1293 assert.Equal(t, 200, st.rw.Code)
1294 assert.Equal(t, st.rw.Body.String(), "signatures match")
1297func TestGetRedirect(t *testing.T) {
1298 options := NewOptions()
1299 _ = options.Validate()
1300 require.NotEmpty(t, options.ProxyPrefix)
1301 proxy := NewOAuthProxy(options, func(s string) bool { return false })
1306 expectedRedirect string
1309 name: "request outside of ProxyPrefix redirects to original URL",
1311 expectedRedirect: "/foo/bar",
1314 name: "request under ProxyPrefix redirects to root",
1315 url: proxy.ProxyPrefix + "/foo/bar",
1316 expectedRedirect: "/",
1319 for _, tt := range tests {
1320 t.Run(tt.name, func(t *testing.T) {
1321 req, _ := http.NewRequest("GET", tt.url, nil)
1322 redirect, err := proxy.GetRedirect(req)
1324 assert.NoError(t, err)
1325 assert.Equal(t, tt.expectedRedirect, redirect)
1330type ajaxRequestTest struct {
1335func newAjaxRequestTest() *ajaxRequestTest {
1336 test := &ajaxRequestTest{}
1337 test.opts = NewOptions()
1338 test.opts.CookieSecret = "sdflsw"
1339 test.opts.ClientID = "gkljfdl"
1340 test.opts.ClientSecret = "sdflkjs"
1341 test.opts.Validate()
1342 test.proxy = NewOAuthProxy(test.opts, func(email string) bool {
1348func (test *ajaxRequestTest) getEndpoint(endpoint string, header http.Header) (int, http.Header, error) {
1349 rw := httptest.NewRecorder()
1350 req, err := http.NewRequest(http.MethodGet, endpoint, strings.NewReader(""))
1355 test.proxy.ServeHTTP(rw, req)
1356 return rw.Code, rw.Header(), nil
1359func testAjaxUnauthorizedRequest(t *testing.T, header http.Header) {
1360 test := newAjaxRequestTest()
1363 code, rh, err := test.getEndpoint(endpoint, header)
1364 assert.NoError(t, err)
1365 assert.Equal(t, http.StatusUnauthorized, code)
1366 mime := rh.Get("Content-Type")
1367 assert.Equal(t, applicationJSON, mime)
1369func TestAjaxUnauthorizedRequest1(t *testing.T) {
1370 header := make(http.Header)
1371 header.Add("accept", applicationJSON)
1373 testAjaxUnauthorizedRequest(t, header)
1376func TestAjaxUnauthorizedRequest2(t *testing.T) {
1377 header := make(http.Header)
1378 header.Add("Accept", applicationJSON)
1380 testAjaxUnauthorizedRequest(t, header)
1383func TestAjaxForbiddendRequest(t *testing.T) {
1384 test := newAjaxRequestTest()
1386 header := make(http.Header)
1387 code, rh, err := test.getEndpoint(endpoint, header)
1388 assert.NoError(t, err)
1389 assert.Equal(t, http.StatusForbidden, code)
1390 mime := rh.Get("Content-Type")
1391 assert.NotEqual(t, applicationJSON, mime)
1394func TestClearSplitCookie(t *testing.T) {
1395 opts := NewOptions()
1396 opts.CookieName = "oauth2"
1397 opts.CookieDomain = "abc"
1398 store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.CookieOptions)
1399 assert.Equal(t, err, nil)
1400 p := OAuthProxy{CookieName: opts.CookieName, CookieDomain: opts.CookieDomain, sessionStore: store}
1401 var rw = httptest.NewRecorder()
1402 req := httptest.NewRequest("get", "/", nil)
1404 req.AddCookie(&http.Cookie{
1408 req.AddCookie(&http.Cookie{
1412 req.AddCookie(&http.Cookie{
1417 p.ClearSessionCookie(rw, req)
1418 header := rw.Header()
1420 assert.Equal(t, 2, len(header["Set-Cookie"]), "should have 3 set-cookie header entries")
1423func TestClearSingleCookie(t *testing.T) {
1424 opts := NewOptions()
1425 opts.CookieName = "oauth2"
1426 opts.CookieDomain = "abc"
1427 store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.CookieOptions)
1428 assert.Equal(t, err, nil)
1429 p := OAuthProxy{CookieName: opts.CookieName, CookieDomain: opts.CookieDomain, sessionStore: store}
1430 var rw = httptest.NewRecorder()
1431 req := httptest.NewRequest("get", "/", nil)
1433 req.AddCookie(&http.Cookie{
1437 req.AddCookie(&http.Cookie{
1442 p.ClearSessionCookie(rw, req)
1443 header := rw.Header()
1445 assert.Equal(t, 1, len(header["Set-Cookie"]), "should have 1 set-cookie header entries")
1448type NoOpKeySet struct {
1451func (NoOpKeySet) VerifySignature(ctx context.Context, jwt string) (payload []byte, err error) {
1452 splitStrings := strings.Split(jwt, ".")
1453 payloadString := splitStrings[1]
1454 jsonString, err := base64.RawURLEncoding.DecodeString(payloadString)
1455 return []byte(jsonString), err
1458func TestGetJwtSession(t *testing.T) {
1461 "sub": "1234567890",
1462 "aud": "https://test.myapp.com",
1464 "email": "john@example.com",
1465 "iss": "https://issuer.example.com",
1470 goodJwt := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9." +
1471 "eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjoiaHR0cHM6Ly90ZXN0Lm15YXBwLmNvbSIsIm5hbWUiOiJKb2huIERvZSIsImVtY" +
1472 "WlsIjoiam9obkBleGFtcGxlLmNvbSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwiaWF0IjoxNTUzNjkxMj" +
1473 "E1LCJleHAiOjE5MTIxNTE4MjF9." +
1474 "rLVyzOnEldUq_pNkfa-WiV8TVJYWyZCaM2Am_uo8FGg11zD7l-qmz3x1seTvqpH6Y0Ty00fmv6dJnGnC8WMnPXQiodRTfhBSe" +
1475 "OKZMu0HkMD2sg52zlKkbfLTO6ic5VnbVgwjjrB8am_Ta6w7kyFUaB5C1BsIrrLMldkWEhynbb8"
1477 keyset := NoOpKeySet{}
1478 verifier := oidc.NewVerifier("https://issuer.example.com", keyset,
1479 &oidc.Config{ClientID: "https://test.myapp.com", SkipExpiryCheck: true})
1481 test := NewAuthOnlyEndpointTest(func(opts *Options) {
1482 opts.PassAuthorization = true
1483 opts.SetAuthorization = true
1484 opts.SetXAuthRequest = true
1485 opts.SkipJwtBearerTokens = true
1486 opts.jwtBearerVerifiers = append(opts.jwtBearerVerifiers, verifier)
1488 tp, _ := test.proxy.provider.(*TestProvider)
1489 tp.GroupValidator = func(s string) bool {
1493 authHeader := fmt.Sprintf("Bearer %s", goodJwt)
1494 test.req.Header = map[string][]string{
1495 "Authorization": {authHeader},
1499 session, _ := test.proxy.GetJwtSession(test.req)
1500 assert.Equal(t, session.User, "john@example.com")
1501 assert.Equal(t, session.Email, "john@example.com")
1502 assert.Equal(t, session.ExpiresOn, time.Unix(1912151821, 0))
1503 assert.Equal(t, session.IDToken, goodJwt)
1505 test.proxy.ServeHTTP(test.rw, test.req)
1506 if test.rw.Code >= 400 {
1507 t.Fatalf("expected 3xx got %d", test.rw.Code)
1510 // Check PassAuthorization, should overwrite Basic header
1511 assert.Equal(t, test.req.Header.Get("Authorization"), authHeader)
1512 assert.Equal(t, test.req.Header.Get("X-Forwarded-User"), "john@example.com")
1513 assert.Equal(t, test.req.Header.Get("X-Forwarded-Email"), "john@example.com")
1515 // SetAuthorization and SetXAuthRequest
1516 assert.Equal(t, test.rw.Header().Get("Authorization"), authHeader)
1517 assert.Equal(t, test.rw.Header().Get("X-Auth-Request-User"), "john@example.com")
1518 assert.Equal(t, test.rw.Header().Get("X-Auth-Request-Email"), "john@example.com")
1521func TestFindJwtBearerToken(t *testing.T) {
1522 p := OAuthProxy{CookieName: "oauth2", CookieDomain: "abc"}
1523 getReq := &http.Request{URL: &url.URL{Scheme: "http", Host: "example.com"}}
1525 validToken := "eyJfoobar.eyJfoobar.12345asdf"
1529 getReq.Header = map[string][]string{
1530 "Authorization": {fmt.Sprintf("Bearer %s", validToken)},
1533 token, _ = p.findBearerToken(getReq)
1534 assert.Equal(t, validToken, token)
1536 // Basic - no password
1537 getReq.SetBasicAuth(token, "")
1538 token, _ = p.findBearerToken(getReq)
1539 assert.Equal(t, validToken, token)
1541 // Basic - sentinel password
1542 getReq.SetBasicAuth(token, "x-oauth-basic")
1543 token, _ = p.findBearerToken(getReq)
1544 assert.Equal(t, validToken, token)
1546 // Basic - any username, password matching jwt pattern
1547 getReq.SetBasicAuth("any-username-you-could-wish-for", token)
1548 token, _ = p.findBearerToken(getReq)
1549 assert.Equal(t, validToken, token)
1551 failures := []string{
1553 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1555 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA",
1556 // Invalid encrypted key
1557 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.//////.dGVzdA.dGVzdA.dGVzdA",
1559 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.//////.dGVzdA.dGVzdA",
1560 // Invalid ciphertext
1561 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.//////.dGVzdA",
1563 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.//////",
1565 "W10.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1567 "######.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1568 // Missing alc/enc params
1569 "e30.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1572 for _, failure := range failures {
1573 getReq.Header = map[string][]string{
1574 "Authorization": {fmt.Sprintf("Bearer %s", failure)},
1576 _, err := p.findBearerToken(getReq)
1577 assert.Error(t, err)
1580 fmt.Printf("%s", token)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list