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{"foo.bar", ".bar.foo"}
188 proxy := NewOAuthProxy(opts, func(string) bool { return true })
190 noRD := proxy.IsValidRedirect("")
191 assert.Equal(t, false, noRD)
193 singleSlash := proxy.IsValidRedirect("/redirect")
194 assert.Equal(t, true, singleSlash)
196 doubleSlash := proxy.IsValidRedirect("//redirect")
197 assert.Equal(t, false, doubleSlash)
199 validHTTP := proxy.IsValidRedirect("http://foo.bar/redirect")
200 assert.Equal(t, true, validHTTP)
202 validHTTPS := proxy.IsValidRedirect("https://foo.bar/redirect")
203 assert.Equal(t, true, validHTTPS)
205 invalidHTTPSubdomain := proxy.IsValidRedirect("http://baz.foo.bar/redirect")
206 assert.Equal(t, false, invalidHTTPSubdomain)
208 invalidHTTPSSubdomain := proxy.IsValidRedirect("https://baz.foo.bar/redirect")
209 assert.Equal(t, false, invalidHTTPSSubdomain)
211 validHTTPSubdomain := proxy.IsValidRedirect("http://baz.bar.foo/redirect")
212 assert.Equal(t, true, validHTTPSubdomain)
214 validHTTPSSubdomain := proxy.IsValidRedirect("https://baz.bar.foo/redirect")
215 assert.Equal(t, true, validHTTPSSubdomain)
217 invalidHTTP1 := proxy.IsValidRedirect("http://foo.bar.evil.corp/redirect")
218 assert.Equal(t, false, invalidHTTP1)
220 invalidHTTPS1 := proxy.IsValidRedirect("https://foo.bar.evil.corp/redirect")
221 assert.Equal(t, false, invalidHTTPS1)
223 invalidHTTP2 := proxy.IsValidRedirect("http://evil.corp/redirect?rd=foo.bar")
224 assert.Equal(t, false, invalidHTTP2)
226 invalidHTTPS2 := proxy.IsValidRedirect("https://evil.corp/redirect?rd=foo.bar")
227 assert.Equal(t, false, invalidHTTPS2)
230type TestProvider struct {
231 *providers.ProviderData
234 GroupValidator func(string) bool
237func NewTestProvider(providerURL *url.URL, emailAddress string) *TestProvider {
238 return &TestProvider{
239 ProviderData: &providers.ProviderData{
240 ProviderName: "Test Provider",
243 Host: providerURL.Host,
244 Path: "/oauth/authorize",
248 Host: providerURL.Host,
249 Path: "/oauth/token",
251 ProfileURL: &url.URL{
253 Host: providerURL.Host,
254 Path: "/api/v1/profile",
256 Scope: "profile.email",
258 EmailAddress: emailAddress,
259 GroupValidator: func(s string) bool {
265func (tp *TestProvider) GetEmailAddress(session *sessions.SessionState) (string, error) {
266 return tp.EmailAddress, nil
269func (tp *TestProvider) ValidateSessionState(session *sessions.SessionState) bool {
273func (tp *TestProvider) ValidateGroup(email string) bool {
274 if tp.GroupValidator != nil {
275 return tp.GroupValidator(email)
280func TestBasicAuthPassword(t *testing.T) {
281 providerServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
282 logger.Printf("%#v", r)
286 payload = `{"access_token": "my_auth_token"}`
288 payload = r.Header.Get("Authorization")
290 payload = "No Authorization header found."
294 w.Write([]byte(payload))
297 opts.Upstreams = append(opts.Upstreams, providerServer.URL)
298 // The CookieSecret must be 32 bytes in order to create the AES
300 opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
301 opts.ClientID = "dlgkj"
302 opts.ClientSecret = "alkgret"
303 opts.CookieSecure = false
304 opts.PassBasicAuth = true
305 opts.PassUserHeaders = true
306 opts.BasicAuthPassword = "This is a secure password"
309 providerURL, _ := url.Parse(providerServer.URL)
310 const emailAddress = "john.doe@example.com"
312 opts.provider = NewTestProvider(providerURL, emailAddress)
313 proxy := NewOAuthProxy(opts, func(email string) bool {
314 return email == emailAddress
317 rw := httptest.NewRecorder()
318 req, _ := http.NewRequest("GET", "/oauth2/callback?code=callback_code&state=nonce:",
319 strings.NewReader(""))
320 req.AddCookie(proxy.MakeCSRFCookie(req, "nonce", proxy.CookieExpire, time.Now()))
321 proxy.ServeHTTP(rw, req)
323 t.Fatalf("expected 3xx got %d", rw.Code)
325 cookie := rw.HeaderMap["Set-Cookie"][1]
327 cookieName := proxy.CookieName
329 keyPrefix := cookieName + "="
331 for _, field := range strings.Split(cookie, "; ") {
332 value = strings.TrimPrefix(field, keyPrefix)
340 req, _ = http.NewRequest("GET", "/", strings.NewReader(""))
341 req.AddCookie(&http.Cookie{
345 Expires: time.Now().Add(time.Duration(24)),
348 req.AddCookie(proxy.MakeCSRFCookie(req, "nonce", proxy.CookieExpire, time.Now()))
350 rw = httptest.NewRecorder()
351 proxy.ServeHTTP(rw, req)
353 // The username in the basic auth credentials is expected to be equal to the email address from the
354 // auth response, so we use the same variable here.
355 expectedHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(emailAddress+":"+opts.BasicAuthPassword))
356 assert.Equal(t, expectedHeader, rw.Body.String())
357 providerServer.Close()
360type PassAccessTokenTest struct {
361 providerServer *httptest.Server
366type PassAccessTokenTestOptions struct {
371func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTest {
372 t := &PassAccessTokenTest{}
374 t.providerServer = httptest.NewServer(
375 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
379 payload = `{"access_token": "my_auth_token"}`
381 payload = r.Header.Get("X-Forwarded-Access-Token")
383 payload = "No access token found."
387 w.Write([]byte(payload))
390 t.opts = NewOptions()
391 t.opts.Upstreams = append(t.opts.Upstreams, t.providerServer.URL)
392 if opts.ProxyUpstream != "" {
393 t.opts.Upstreams = append(t.opts.Upstreams, opts.ProxyUpstream)
395 // The CookieSecret must be 32 bytes in order to create the AES
397 t.opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
398 t.opts.ClientID = "slgkj"
399 t.opts.ClientSecret = "gfjgojl"
400 t.opts.CookieSecure = false
401 t.opts.PassAccessToken = opts.PassAccessToken
404 providerURL, _ := url.Parse(t.providerServer.URL)
405 const emailAddress = "michael.bland@gsa.gov"
407 t.opts.provider = NewTestProvider(providerURL, emailAddress)
408 t.proxy = NewOAuthProxy(t.opts, func(email string) bool {
409 return email == emailAddress
414func (patTest *PassAccessTokenTest) Close() {
415 patTest.providerServer.Close()
418func (patTest *PassAccessTokenTest) getCallbackEndpoint() (httpCode int,
420 rw := httptest.NewRecorder()
421 req, err := http.NewRequest("GET", "/oauth2/callback?code=callback_code&state=nonce:",
422 strings.NewReader(""))
426 req.AddCookie(patTest.proxy.MakeCSRFCookie(req, "nonce", time.Hour, time.Now()))
427 patTest.proxy.ServeHTTP(rw, req)
428 return rw.Code, rw.HeaderMap["Set-Cookie"][1]
431// getEndpointWithCookie makes a requests againt the oauthproxy with passed requestPath
432// and cookie and returns body and status code.
433func (patTest *PassAccessTokenTest) getEndpointWithCookie(cookie string, endpoint string) (httpCode int, accessToken string) {
434 cookieName := patTest.proxy.CookieName
436 keyPrefix := cookieName + "="
438 for _, field := range strings.Split(cookie, "; ") {
439 value = strings.TrimPrefix(field, keyPrefix)
450 req, err := http.NewRequest("GET", endpoint, strings.NewReader(""))
454 req.AddCookie(&http.Cookie{
458 Expires: time.Now().Add(time.Duration(24)),
462 rw := httptest.NewRecorder()
463 patTest.proxy.ServeHTTP(rw, req)
464 return rw.Code, rw.Body.String()
467func TestForwardAccessTokenUpstream(t *testing.T) {
468 patTest := NewPassAccessTokenTest(PassAccessTokenTestOptions{
469 PassAccessToken: true,
471 defer patTest.Close()
473 // A successful validation will redirect and set the auth cookie.
474 code, cookie := patTest.getCallbackEndpoint()
476 t.Fatalf("expected 302; got %d", code)
478 assert.NotEqual(t, nil, cookie)
480 // Now we make a regular request; the access_token from the cookie is
481 // forwarded as the "X-Forwarded-Access-Token" header. The token is
482 // read by the test provider server and written in the response body.
483 code, payload := patTest.getEndpointWithCookie(cookie, "/")
485 t.Fatalf("expected 200; got %d", code)
487 assert.Equal(t, "my_auth_token", payload)
490func TestStaticProxyUpstream(t *testing.T) {
491 patTest := NewPassAccessTokenTest(PassAccessTokenTestOptions{
492 PassAccessToken: true,
493 ProxyUpstream: "static://200/static-proxy",
496 defer patTest.Close()
498 // A successful validation will redirect and set the auth cookie.
499 code, cookie := patTest.getCallbackEndpoint()
501 t.Fatalf("expected 302; got %d", code)
503 assert.NotEqual(t, nil, cookie)
505 // Now we make a regular request againts the upstream proxy; And validate
506 // the returned status code through the static proxy.
507 code, payload := patTest.getEndpointWithCookie(cookie, "/static-proxy")
509 t.Fatalf("expected 200; got %d", code)
511 assert.Equal(t, "Authenticated", payload)
514func TestDoNotForwardAccessTokenUpstream(t *testing.T) {
515 patTest := NewPassAccessTokenTest(PassAccessTokenTestOptions{
516 PassAccessToken: false,
518 defer patTest.Close()
520 // A successful validation will redirect and set the auth cookie.
521 code, cookie := patTest.getCallbackEndpoint()
523 t.Fatalf("expected 302; got %d", code)
525 assert.NotEqual(t, nil, cookie)
527 // Now we make a regular request, but the access token header should
529 code, payload := patTest.getEndpointWithCookie(cookie, "/")
531 t.Fatalf("expected 200; got %d", code)
533 assert.Equal(t, "No access token found.", payload)
536type SignInPageTest struct {
539 signInRegexp *regexp.Regexp
540 signInProviderRegexp *regexp.Regexp
543const signInRedirectPattern = `<input type="hidden" name="rd" value="(.*)">`
544const signInSkipProvider = `>Found<`
546func NewSignInPageTest(skipProvider bool) *SignInPageTest {
547 var sipTest SignInPageTest
549 sipTest.opts = NewOptions()
550 sipTest.opts.CookieSecret = "adklsj2"
551 sipTest.opts.ClientID = "lkdgj"
552 sipTest.opts.ClientSecret = "sgiufgoi"
553 sipTest.opts.SkipProviderButton = skipProvider
554 sipTest.opts.Validate()
556 sipTest.proxy = NewOAuthProxy(sipTest.opts, func(email string) bool {
559 sipTest.signInRegexp = regexp.MustCompile(signInRedirectPattern)
560 sipTest.signInProviderRegexp = regexp.MustCompile(signInSkipProvider)
565func (sipTest *SignInPageTest) GetEndpoint(endpoint string) (int, string) {
566 rw := httptest.NewRecorder()
567 req, _ := http.NewRequest("GET", endpoint, strings.NewReader(""))
568 sipTest.proxy.ServeHTTP(rw, req)
569 return rw.Code, rw.Body.String()
572func TestSignInPageIncludesTargetRedirect(t *testing.T) {
573 sipTest := NewSignInPageTest(false)
574 const endpoint = "/some/random/endpoint"
576 code, body := sipTest.GetEndpoint(endpoint)
577 assert.Equal(t, 403, code)
579 match := sipTest.signInRegexp.FindStringSubmatch(body)
581 t.Fatal("Did not find pattern in body: " +
582 signInRedirectPattern + "\nBody:\n" + body)
584 if match[1] != endpoint {
585 t.Fatal(`expected redirect to "` + endpoint +
586 `", but was "` + match[1] + `"`)
590func TestSignInPageDirectAccessRedirectsToRoot(t *testing.T) {
591 sipTest := NewSignInPageTest(false)
592 code, body := sipTest.GetEndpoint("/oauth2/sign_in")
593 assert.Equal(t, 200, code)
595 match := sipTest.signInRegexp.FindStringSubmatch(body)
597 t.Fatal("Did not find pattern in body: " +
598 signInRedirectPattern + "\nBody:\n" + body)
601 t.Fatal(`expected redirect to "/", but was "` + match[1] + `"`)
605func TestSignInPageSkipProvider(t *testing.T) {
606 sipTest := NewSignInPageTest(true)
607 const endpoint = "/some/random/endpoint"
609 code, body := sipTest.GetEndpoint(endpoint)
610 assert.Equal(t, 302, code)
612 match := sipTest.signInProviderRegexp.FindStringSubmatch(body)
614 t.Fatal("Did not find pattern in body: " +
615 signInSkipProvider + "\nBody:\n" + body)
619func TestSignInPageSkipProviderDirect(t *testing.T) {
620 sipTest := NewSignInPageTest(true)
621 const endpoint = "/sign_in"
623 code, body := sipTest.GetEndpoint(endpoint)
624 assert.Equal(t, 302, code)
626 match := sipTest.signInProviderRegexp.FindStringSubmatch(body)
628 t.Fatal("Did not find pattern in body: " +
629 signInSkipProvider + "\nBody:\n" + body)
633type ProcessCookieTest struct {
636 rw *httptest.ResponseRecorder
638 provider TestProvider
643type ProcessCookieTestOpts struct {
644 providerValidateCookieResponse bool
647type OptionsModifier func(*Options)
649func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifier) *ProcessCookieTest {
650 var pcTest ProcessCookieTest
652 pcTest.opts = NewOptions()
653 for _, modifier := range modifiers {
654 modifier(pcTest.opts)
656 pcTest.opts.ClientID = "asdfljk"
657 pcTest.opts.ClientSecret = "lkjfdsig"
658 pcTest.opts.CookieSecret = "0123456789abcdefabcd"
659 // First, set the CookieRefresh option so proxy.AesCipher is created,
660 // needed to encrypt the access_token.
661 pcTest.opts.CookieRefresh = time.Hour
662 pcTest.opts.Validate()
664 pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
665 return pcTest.validateUser
667 pcTest.proxy.provider = &TestProvider{
668 ValidToken: opts.providerValidateCookieResponse,
671 // Now, zero-out proxy.CookieRefresh for the cases that don't involve
672 // access_token validation.
673 pcTest.proxy.CookieRefresh = time.Duration(0)
674 pcTest.rw = httptest.NewRecorder()
675 pcTest.req, _ = http.NewRequest("GET", "/", strings.NewReader(""))
676 pcTest.validateUser = true
680func NewProcessCookieTestWithDefaults() *ProcessCookieTest {
681 return NewProcessCookieTest(ProcessCookieTestOpts{
682 providerValidateCookieResponse: true,
686func NewProcessCookieTestWithOptionsModifiers(modifiers ...OptionsModifier) *ProcessCookieTest {
687 return NewProcessCookieTest(ProcessCookieTestOpts{
688 providerValidateCookieResponse: true,
692func (p *ProcessCookieTest) SaveSession(s *sessions.SessionState) error {
693 err := p.proxy.SaveSession(p.rw, p.req, s)
697 for _, cookie := range p.rw.Result().Cookies() {
698 p.req.AddCookie(cookie)
703func (p *ProcessCookieTest) LoadCookiedSession() (*sessions.SessionState, error) {
704 return p.proxy.LoadCookiedSession(p.req)
707func TestLoadCookiedSession(t *testing.T) {
708 pcTest := NewProcessCookieTestWithDefaults()
710 startSession := &sessions.SessionState{Email: "john.doe@example.com", AccessToken: "my_access_token", CreatedAt: time.Now()}
711 pcTest.SaveSession(startSession)
713 session, err := pcTest.LoadCookiedSession()
714 assert.Equal(t, nil, err)
715 assert.Equal(t, startSession.Email, session.Email)
716 assert.Equal(t, "john.doe@example.com", session.User)
717 assert.Equal(t, startSession.AccessToken, session.AccessToken)
720func TestProcessCookieNoCookieError(t *testing.T) {
721 pcTest := NewProcessCookieTestWithDefaults()
723 session, err := pcTest.LoadCookiedSession()
724 assert.Equal(t, "Cookie \"_oauth2_proxy\" not present", err.Error())
726 t.Errorf("expected nil session. got %#v", session)
730func TestProcessCookieRefreshNotSet(t *testing.T) {
731 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
732 opts.CookieExpire = time.Duration(23) * time.Hour
734 reference := time.Now().Add(time.Duration(-2) * time.Hour)
736 startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
737 pcTest.SaveSession(startSession)
739 session, err := pcTest.LoadCookiedSession()
740 assert.Equal(t, nil, err)
741 if session.Age() < time.Duration(-2)*time.Hour {
742 t.Errorf("cookie too young %v", session.Age())
744 assert.Equal(t, startSession.Email, session.Email)
747func TestProcessCookieFailIfCookieExpired(t *testing.T) {
748 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
749 opts.CookieExpire = time.Duration(24) * time.Hour
751 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
752 startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
753 pcTest.SaveSession(startSession)
755 session, err := pcTest.LoadCookiedSession()
756 assert.NotEqual(t, nil, err)
758 t.Errorf("expected nil session %#v", session)
762func TestProcessCookieFailIfRefreshSetAndCookieExpired(t *testing.T) {
763 pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
764 opts.CookieExpire = time.Duration(24) * time.Hour
766 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
767 startSession := &sessions.SessionState{Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
768 pcTest.SaveSession(startSession)
770 pcTest.proxy.CookieRefresh = time.Hour
771 session, err := pcTest.LoadCookiedSession()
772 assert.NotEqual(t, nil, err)
774 t.Errorf("expected nil session %#v", session)
778func NewUserInfoEndpointTest() *ProcessCookieTest {
779 pcTest := NewProcessCookieTestWithDefaults()
780 pcTest.req, _ = http.NewRequest("GET",
781 pcTest.opts.ProxyPrefix+"/userinfo", nil)
785func TestUserInfoEndpointAccepted(t *testing.T) {
786 test := NewUserInfoEndpointTest()
787 startSession := &sessions.SessionState{
788 Email: "john.doe@example.com", AccessToken: "my_access_token"}
789 test.SaveSession(startSession)
791 test.proxy.ServeHTTP(test.rw, test.req)
792 assert.Equal(t, http.StatusOK, test.rw.Code)
793 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
794 assert.Equal(t, "{\"email\":\"john.doe@example.com\"}\n", string(bodyBytes))
797func TestUserInfoEndpointUnauthorizedOnNoCookieSetError(t *testing.T) {
798 test := NewUserInfoEndpointTest()
800 test.proxy.ServeHTTP(test.rw, test.req)
801 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
804func NewAuthOnlyEndpointTest(modifiers ...OptionsModifier) *ProcessCookieTest {
805 pcTest := NewProcessCookieTestWithOptionsModifiers(modifiers...)
806 pcTest.req, _ = http.NewRequest("GET",
807 pcTest.opts.ProxyPrefix+"/auth", nil)
811func TestAuthOnlyEndpointAccepted(t *testing.T) {
812 test := NewAuthOnlyEndpointTest()
813 startSession := &sessions.SessionState{
814 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: time.Now()}
815 test.SaveSession(startSession)
817 test.proxy.ServeHTTP(test.rw, test.req)
818 assert.Equal(t, http.StatusAccepted, test.rw.Code)
819 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
820 assert.Equal(t, "", string(bodyBytes))
823func TestAuthOnlyEndpointUnauthorizedOnNoCookieSetError(t *testing.T) {
824 test := NewAuthOnlyEndpointTest()
826 test.proxy.ServeHTTP(test.rw, test.req)
827 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
828 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
829 assert.Equal(t, "unauthorized request\n", string(bodyBytes))
832func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
833 test := NewAuthOnlyEndpointTest(func(opts *Options) {
834 opts.CookieExpire = time.Duration(24) * time.Hour
836 reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
837 startSession := &sessions.SessionState{
838 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: reference}
839 test.SaveSession(startSession)
841 test.proxy.ServeHTTP(test.rw, test.req)
842 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
843 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
844 assert.Equal(t, "unauthorized request\n", string(bodyBytes))
847func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure(t *testing.T) {
848 test := NewAuthOnlyEndpointTest()
849 startSession := &sessions.SessionState{
850 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: time.Now()}
851 test.SaveSession(startSession)
852 test.validateUser = false
854 test.proxy.ServeHTTP(test.rw, test.req)
855 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
856 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
857 assert.Equal(t, "unauthorized request\n", string(bodyBytes))
860func TestAuthOnlyEndpointUnauthorizedOnProviderGroupValidationFailure(t *testing.T) {
861 test := NewAuthOnlyEndpointTest()
862 startSession := &sessions.SessionState{
863 Email: "michael.bland@gsa.gov", AccessToken: "my_access_token", CreatedAt: time.Now()}
864 test.SaveSession(startSession)
865 provider := &TestProvider{
867 GroupValidator: func(s string) bool {
872 test.proxy.provider = provider
873 test.proxy.ServeHTTP(test.rw, test.req)
874 assert.Equal(t, http.StatusUnauthorized, test.rw.Code)
875 bodyBytes, _ := ioutil.ReadAll(test.rw.Body)
876 assert.Equal(t, "unauthorized request\n", string(bodyBytes))
879func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
880 var pcTest ProcessCookieTest
882 pcTest.opts = NewOptions()
883 pcTest.opts.SetXAuthRequest = true
884 pcTest.opts.Validate()
886 pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
887 return pcTest.validateUser
889 pcTest.proxy.provider = &TestProvider{
893 pcTest.validateUser = true
895 pcTest.rw = httptest.NewRecorder()
896 pcTest.req, _ = http.NewRequest("GET",
897 pcTest.opts.ProxyPrefix+"/auth", nil)
899 startSession := &sessions.SessionState{
900 User: "oauth_user", Email: "oauth_user@example.com", AccessToken: "oauth_token", CreatedAt: time.Now()}
901 pcTest.SaveSession(startSession)
903 pcTest.proxy.ServeHTTP(pcTest.rw, pcTest.req)
904 assert.Equal(t, http.StatusAccepted, pcTest.rw.Code)
905 assert.Equal(t, "oauth_user", pcTest.rw.HeaderMap["X-Auth-Request-User"][0])
906 assert.Equal(t, "oauth_user@example.com", pcTest.rw.HeaderMap["X-Auth-Request-Email"][0])
909func TestAuthSkippedForPreflightRequests(t *testing.T) {
910 upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
912 w.Write([]byte("response"))
914 defer upstream.Close()
917 opts.Upstreams = append(opts.Upstreams, upstream.URL)
918 opts.ClientID = "aljsal"
919 opts.ClientSecret = "jglkfsdgj"
920 opts.CookieSecret = "dkfjgdls"
921 opts.SkipAuthPreflight = true
924 upstreamURL, _ := url.Parse(upstream.URL)
925 opts.provider = NewTestProvider(upstreamURL, "")
927 proxy := NewOAuthProxy(opts, func(string) bool { return false })
928 rw := httptest.NewRecorder()
929 req, _ := http.NewRequest("OPTIONS", "/preflight-request", nil)
930 proxy.ServeHTTP(rw, req)
932 assert.Equal(t, 200, rw.Code)
933 assert.Equal(t, "response", rw.Body.String())
936type SignatureAuthenticator struct {
937 auth hmacauth.HmacAuth
940func (v *SignatureAuthenticator) Authenticate(w http.ResponseWriter, r *http.Request) {
941 result, headerSig, computedSig := v.auth.AuthenticateRequest(r)
942 if result == hmacauth.ResultNoSignature {
943 w.Write([]byte("no signature received"))
944 } else if result == hmacauth.ResultMatch {
945 w.Write([]byte("signatures match"))
946 } else if result == hmacauth.ResultMismatch {
947 w.Write([]byte("signatures do not match:" +
948 "\n received: " + headerSig +
949 "\n computed: " + computedSig))
951 panic("Unknown result value: " + result.String())
955type SignatureTest struct {
957 upstream *httptest.Server
959 provider *httptest.Server
961 rw *httptest.ResponseRecorder
962 authenticator *SignatureAuthenticator
965func NewSignatureTest() *SignatureTest {
967 opts.CookieSecret = "cookie secret"
968 opts.ClientID = "client ID"
969 opts.ClientSecret = "client secret"
970 opts.EmailDomains = []string{"acm.org"}
972 authenticator := &SignatureAuthenticator{}
973 upstream := httptest.NewServer(
974 http.HandlerFunc(authenticator.Authenticate))
975 upstreamURL, _ := url.Parse(upstream.URL)
976 opts.Upstreams = append(opts.Upstreams, upstream.URL)
978 providerHandler := func(w http.ResponseWriter, r *http.Request) {
979 w.Write([]byte(`{"access_token": "my_auth_token"}`))
981 provider := httptest.NewServer(http.HandlerFunc(providerHandler))
982 providerURL, _ := url.Parse(provider.URL)
983 opts.provider = NewTestProvider(providerURL, "mbland@acm.org")
985 return &SignatureTest{
991 httptest.NewRecorder(),
996func (st *SignatureTest) Close() {
1001// fakeNetConn simulates an http.Request.Body buffer that will be consumed
1002// when it is read by the hmacauth.HmacAuth if not handled properly. See:
1003// https://github.com/18F/hmacauth/pull/4
1004type fakeNetConn struct {
1008func (fnc *fakeNetConn) Read(p []byte) (n int, err error) {
1009 if bodyLen := len(fnc.reqBody); bodyLen != 0 {
1010 copy(p, fnc.reqBody)
1012 return bodyLen, io.EOF
1017func (st *SignatureTest) MakeRequestWithExpectedKey(method, body, key string) {
1018 err := st.opts.Validate()
1022 proxy := NewOAuthProxy(st.opts, func(email string) bool { return true })
1024 var bodyBuf io.ReadCloser
1026 bodyBuf = ioutil.NopCloser(&fakeNetConn{reqBody: body})
1028 req := httptest.NewRequest(method, "/foo/bar", bodyBuf)
1029 req.Header = st.header
1031 state := &sessions.SessionState{
1032 Email: "mbland@acm.org", AccessToken: "my_access_token"}
1033 err = proxy.SaveSession(st.rw, req, state)
1037 for _, c := range st.rw.Result().Cookies() {
1040 // This is used by the upstream to validate the signature.
1041 st.authenticator.auth = hmacauth.NewHmacAuth(
1042 crypto.SHA1, []byte(key), SignatureHeader, SignatureHeaders)
1043 proxy.ServeHTTP(st.rw, req)
1046func TestNoRequestSignature(t *testing.T) {
1047 st := NewSignatureTest()
1049 st.MakeRequestWithExpectedKey("GET", "", "")
1050 assert.Equal(t, 200, st.rw.Code)
1051 assert.Equal(t, st.rw.Body.String(), "no signature received")
1054func TestRequestSignatureGetRequest(t *testing.T) {
1055 st := NewSignatureTest()
1057 st.opts.SignatureKey = "sha1:7d9e1aa87a5954e6f9fc59266b3af9d7c35fda2d"
1058 st.MakeRequestWithExpectedKey("GET", "", "7d9e1aa87a5954e6f9fc59266b3af9d7c35fda2d")
1059 assert.Equal(t, 200, st.rw.Code)
1060 assert.Equal(t, st.rw.Body.String(), "signatures match")
1063func TestRequestSignaturePostRequest(t *testing.T) {
1064 st := NewSignatureTest()
1066 st.opts.SignatureKey = "sha1:d90df39e2d19282840252612dd7c81421a372f61"
1067 payload := `{ "hello": "world!" }`
1068 st.MakeRequestWithExpectedKey("POST", payload, "d90df39e2d19282840252612dd7c81421a372f61")
1069 assert.Equal(t, 200, st.rw.Code)
1070 assert.Equal(t, st.rw.Body.String(), "signatures match")
1073func TestGetRedirect(t *testing.T) {
1074 options := NewOptions()
1075 _ = options.Validate()
1076 require.NotEmpty(t, options.ProxyPrefix)
1077 proxy := NewOAuthProxy(options, func(s string) bool { return false })
1082 expectedRedirect string
1085 name: "request outside of ProxyPrefix redirects to original URL",
1087 expectedRedirect: "/foo/bar",
1090 name: "request under ProxyPrefix redirects to root",
1091 url: proxy.ProxyPrefix + "/foo/bar",
1092 expectedRedirect: "/",
1095 for _, tt := range tests {
1096 t.Run(tt.name, func(t *testing.T) {
1097 req, _ := http.NewRequest("GET", tt.url, nil)
1098 redirect, err := proxy.GetRedirect(req)
1100 assert.NoError(t, err)
1101 assert.Equal(t, tt.expectedRedirect, redirect)
1106type ajaxRequestTest struct {
1111func newAjaxRequestTest() *ajaxRequestTest {
1112 test := &ajaxRequestTest{}
1113 test.opts = NewOptions()
1114 test.opts.CookieSecret = "sdflsw"
1115 test.opts.ClientID = "gkljfdl"
1116 test.opts.ClientSecret = "sdflkjs"
1117 test.opts.Validate()
1118 test.proxy = NewOAuthProxy(test.opts, func(email string) bool {
1124func (test *ajaxRequestTest) getEndpoint(endpoint string, header http.Header) (int, http.Header, error) {
1125 rw := httptest.NewRecorder()
1126 req, err := http.NewRequest(http.MethodGet, endpoint, strings.NewReader(""))
1131 test.proxy.ServeHTTP(rw, req)
1132 return rw.Code, rw.Header(), nil
1135func testAjaxUnauthorizedRequest(t *testing.T, header http.Header) {
1136 test := newAjaxRequestTest()
1139 code, rh, err := test.getEndpoint(endpoint, header)
1140 assert.NoError(t, err)
1141 assert.Equal(t, http.StatusUnauthorized, code)
1142 mime := rh.Get("Content-Type")
1143 assert.Equal(t, applicationJSON, mime)
1145func TestAjaxUnauthorizedRequest1(t *testing.T) {
1146 header := make(http.Header)
1147 header.Add("accept", applicationJSON)
1149 testAjaxUnauthorizedRequest(t, header)
1152func TestAjaxUnauthorizedRequest2(t *testing.T) {
1153 header := make(http.Header)
1154 header.Add("Accept", applicationJSON)
1156 testAjaxUnauthorizedRequest(t, header)
1159func TestAjaxForbiddendRequest(t *testing.T) {
1160 test := newAjaxRequestTest()
1162 header := make(http.Header)
1163 code, rh, err := test.getEndpoint(endpoint, header)
1164 assert.NoError(t, err)
1165 assert.Equal(t, http.StatusForbidden, code)
1166 mime := rh.Get("Content-Type")
1167 assert.NotEqual(t, applicationJSON, mime)
1170func TestClearSplitCookie(t *testing.T) {
1171 opts := NewOptions()
1172 opts.CookieName = "oauth2"
1173 opts.CookieDomain = "abc"
1174 store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.CookieOptions)
1175 assert.Equal(t, err, nil)
1176 p := OAuthProxy{CookieName: opts.CookieName, CookieDomain: opts.CookieDomain, sessionStore: store}
1177 var rw = httptest.NewRecorder()
1178 req := httptest.NewRequest("get", "/", nil)
1180 req.AddCookie(&http.Cookie{
1184 req.AddCookie(&http.Cookie{
1188 req.AddCookie(&http.Cookie{
1193 p.ClearSessionCookie(rw, req)
1194 header := rw.Header()
1196 assert.Equal(t, 2, len(header["Set-Cookie"]), "should have 3 set-cookie header entries")
1199func TestClearSingleCookie(t *testing.T) {
1200 opts := NewOptions()
1201 opts.CookieName = "oauth2"
1202 opts.CookieDomain = "abc"
1203 store, err := cookie.NewCookieSessionStore(&opts.SessionOptions, &opts.CookieOptions)
1204 assert.Equal(t, err, nil)
1205 p := OAuthProxy{CookieName: opts.CookieName, CookieDomain: opts.CookieDomain, sessionStore: store}
1206 var rw = httptest.NewRecorder()
1207 req := httptest.NewRequest("get", "/", nil)
1209 req.AddCookie(&http.Cookie{
1213 req.AddCookie(&http.Cookie{
1218 p.ClearSessionCookie(rw, req)
1219 header := rw.Header()
1221 assert.Equal(t, 1, len(header["Set-Cookie"]), "should have 1 set-cookie header entries")
1224type NoOpKeySet struct {
1227func (NoOpKeySet) VerifySignature(ctx context.Context, jwt string) (payload []byte, err error) {
1228 splitStrings := strings.Split(jwt, ".")
1229 payloadString := splitStrings[1]
1230 jsonString, err := base64.RawURLEncoding.DecodeString(payloadString)
1231 return []byte(jsonString), err
1234func TestGetJwtSession(t *testing.T) {
1237 "sub": "1234567890",
1238 "aud": "https://test.myapp.com",
1240 "email": "john@example.com",
1241 "iss": "https://issuer.example.com",
1246 goodJwt := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9." +
1247 "eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjoiaHR0cHM6Ly90ZXN0Lm15YXBwLmNvbSIsIm5hbWUiOiJKb2huIERvZSIsImVtY" +
1248 "WlsIjoiam9obkBleGFtcGxlLmNvbSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwiaWF0IjoxNTUzNjkxMj" +
1249 "E1LCJleHAiOjE5MTIxNTE4MjF9." +
1250 "rLVyzOnEldUq_pNkfa-WiV8TVJYWyZCaM2Am_uo8FGg11zD7l-qmz3x1seTvqpH6Y0Ty00fmv6dJnGnC8WMnPXQiodRTfhBSe" +
1251 "OKZMu0HkMD2sg52zlKkbfLTO6ic5VnbVgwjjrB8am_Ta6w7kyFUaB5C1BsIrrLMldkWEhynbb8"
1253 keyset := NoOpKeySet{}
1254 verifier := oidc.NewVerifier("https://issuer.example.com", keyset,
1255 &oidc.Config{ClientID: "https://test.myapp.com", SkipExpiryCheck: true})
1257 test := NewAuthOnlyEndpointTest(func(opts *Options) {
1258 opts.PassAuthorization = true
1259 opts.SetAuthorization = true
1260 opts.SetXAuthRequest = true
1261 opts.SkipJwtBearerTokens = true
1262 opts.jwtBearerVerifiers = append(opts.jwtBearerVerifiers, verifier)
1264 tp, _ := test.proxy.provider.(*TestProvider)
1265 tp.GroupValidator = func(s string) bool {
1269 authHeader := fmt.Sprintf("Bearer %s", goodJwt)
1270 test.req.Header = map[string][]string{
1271 "Authorization": {authHeader},
1275 session, _ := test.proxy.GetJwtSession(test.req)
1276 assert.Equal(t, session.User, "john@example.com")
1277 assert.Equal(t, session.Email, "john@example.com")
1278 assert.Equal(t, session.ExpiresOn, time.Unix(1912151821, 0))
1279 assert.Equal(t, session.IDToken, goodJwt)
1281 test.proxy.ServeHTTP(test.rw, test.req)
1282 if test.rw.Code >= 400 {
1283 t.Fatalf("expected 3xx got %d", test.rw.Code)
1286 // Check PassAuthorization, should overwrite Basic header
1287 assert.Equal(t, test.req.Header.Get("Authorization"), authHeader)
1288 assert.Equal(t, test.req.Header.Get("X-Forwarded-User"), "john@example.com")
1289 assert.Equal(t, test.req.Header.Get("X-Forwarded-Email"), "john@example.com")
1291 // SetAuthorization and SetXAuthRequest
1292 assert.Equal(t, test.rw.Header().Get("Authorization"), authHeader)
1293 assert.Equal(t, test.rw.Header().Get("X-Auth-Request-User"), "john@example.com")
1294 assert.Equal(t, test.rw.Header().Get("X-Auth-Request-Email"), "john@example.com")
1297func TestJwtUnauthorizedOnGroupValidationFailure(t *testing.T) {
1298 goodJwt := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9." +
1299 "eyJzdWIiOiIxMjM0NTY3ODkwIiwiYXVkIjoiaHR0cHM6Ly90ZXN0Lm15YXBwLmNvbSIsIm5hbWUiOiJKb2huIERvZSIsImVtY" +
1300 "WlsIjoiam9obkBleGFtcGxlLmNvbSIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwiaWF0IjoxNTUzNjkxMj" +
1301 "E1LCJleHAiOjE5MTIxNTE4MjF9." +
1302 "rLVyzOnEldUq_pNkfa-WiV8TVJYWyZCaM2Am_uo8FGg11zD7l-qmz3x1seTvqpH6Y0Ty00fmv6dJnGnC8WMnPXQiodRTfhBSe" +
1303 "OKZMu0HkMD2sg52zlKkbfLTO6ic5VnbVgwjjrB8am_Ta6w7kyFUaB5C1BsIrrLMldkWEhynbb8"
1305 keyset := NoOpKeySet{}
1306 verifier := oidc.NewVerifier("https://issuer.example.com", keyset,
1307 &oidc.Config{ClientID: "https://test.myapp.com", SkipExpiryCheck: true})
1309 test := NewAuthOnlyEndpointTest(func(opts *Options) {
1310 opts.PassAuthorization = true
1311 opts.SetAuthorization = true
1312 opts.SetXAuthRequest = true
1313 opts.SkipJwtBearerTokens = true
1314 opts.jwtBearerVerifiers = append(opts.jwtBearerVerifiers, verifier)
1316 tp, _ := test.proxy.provider.(*TestProvider)
1317 // Verify ValidateGroup fails JWT authorization
1318 tp.GroupValidator = func(s string) bool {
1322 authHeader := fmt.Sprintf("Bearer %s", goodJwt)
1323 test.req.Header = map[string][]string{
1324 "Authorization": {authHeader},
1326 test.proxy.ServeHTTP(test.rw, test.req)
1327 if test.rw.Code != http.StatusUnauthorized {
1328 t.Fatalf("expected 401 got %d", test.rw.Code)
1332func TestFindJwtBearerToken(t *testing.T) {
1333 p := OAuthProxy{CookieName: "oauth2", CookieDomain: "abc"}
1334 getReq := &http.Request{URL: &url.URL{Scheme: "http", Host: "example.com"}}
1336 validToken := "eyJfoobar.eyJfoobar.12345asdf"
1340 getReq.Header = map[string][]string{
1341 "Authorization": {fmt.Sprintf("Bearer %s", validToken)},
1344 token, _ = p.findBearerToken(getReq)
1345 assert.Equal(t, validToken, token)
1347 // Basic - no password
1348 getReq.SetBasicAuth(token, "")
1349 token, _ = p.findBearerToken(getReq)
1350 assert.Equal(t, validToken, token)
1352 // Basic - sentinel password
1353 getReq.SetBasicAuth(token, "x-oauth-basic")
1354 token, _ = p.findBearerToken(getReq)
1355 assert.Equal(t, validToken, token)
1357 // Basic - any username, password matching jwt pattern
1358 getReq.SetBasicAuth("any-username-you-could-wish-for", token)
1359 token, _ = p.findBearerToken(getReq)
1360 assert.Equal(t, validToken, token)
1362 failures := []string{
1364 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1366 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA",
1367 // Invalid encrypted key
1368 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.//////.dGVzdA.dGVzdA.dGVzdA",
1370 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.//////.dGVzdA.dGVzdA",
1371 // Invalid ciphertext
1372 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.//////.dGVzdA",
1374 "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.//////",
1376 "W10.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1378 "######.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1379 // Missing alc/enc params
1380 "e30.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
1383 for _, failure := range failures {
1384 getReq.Header = map[string][]string{
1385 "Authorization": {fmt.Sprintf("Bearer %s", failure)},
1387 _, err := p.findBearerToken(getReq)
1388 assert.Error(t, err)
1391 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