diff --git a/oauthproxy.go b/oauthproxy.go index 04ab41d..4943bdf 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -262,6 +262,27 @@ func (p *OauthProxy) SetCookie(rw http.ResponseWriter, req *http.Request, val st http.SetCookie(rw, p.MakeCookie(req, val, p.CookieExpire)) } +func (p *OauthProxy) ValidateToken(access_token string) bool { + if access_token == "" || p.oauthValidateUrl == nil { + return false + } + + req, err := http.NewRequest("GET", + p.oauthValidateUrl.String()+"?access_token="+access_token, nil) + if err != nil { + log.Printf("failed building token validation request: %s", err) + return false + } + + httpclient := &http.Client{} + resp, err := httpclient.Do(req) + if err != nil { + log.Printf("token validation request failed: %s", err) + return false + } + return resp.StatusCode == 200 +} + func (p *OauthProxy) ProcessCookie(rw http.ResponseWriter, req *http.Request) (email, user, access_token string, ok bool) { var value string var timestamp time.Time diff --git a/oauthproxy_test.go b/oauthproxy_test.go index c38c31e..e0d6f6b 100644 --- a/oauthproxy_test.go +++ b/oauthproxy_test.go @@ -306,6 +306,90 @@ func TestSignInPageDirectAccessRedirectsToRoot(t *testing.T) { } } +type ValidateTokenTest struct { + opts *Options + proxy *OauthProxy + backend *httptest.Server + response_code int +} + +func NewValidateTokenTest() *ValidateTokenTest { + var vt_test ValidateTokenTest + + vt_test.opts = NewOptions() + vt_test.opts.Upstreams = append(vt_test.opts.Upstreams, "unused") + vt_test.opts.CookieSecret = "foobar" + vt_test.opts.ClientID = "bazquux" + vt_test.opts.ClientSecret = "xyzzyplugh" + vt_test.opts.Validate() + + vt_test.backend = httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/oauth/tokeninfo": + w.WriteHeader(vt_test.response_code) + w.Write([]byte("only code matters; contents disregarded")) + default: + w.WriteHeader(500) + w.Write([]byte("unknown URL")) + } + })) + backend_url, _ := url.Parse(vt_test.backend.URL) + vt_test.opts.provider.Data().ValidateUrl = &url.URL{ + Scheme: "http", + Host: backend_url.Host, + Path: "/oauth/tokeninfo", + } + vt_test.response_code = 200 + + vt_test.proxy = NewOauthProxy(vt_test.opts, func(email string) bool { + return true + }) + return &vt_test +} + +func (vt_test *ValidateTokenTest) Close() { + vt_test.backend.Close() +} + +func TestValidateTokenEmptyToken(t *testing.T) { + vt_test := NewValidateTokenTest() + defer vt_test.Close() + + assert.Equal(t, false, vt_test.proxy.ValidateToken("")) +} + +func TestValidateTokenEmptyValidateUrl(t *testing.T) { + vt_test := NewValidateTokenTest() + defer vt_test.Close() + + vt_test.proxy.oauthValidateUrl = nil + assert.Equal(t, false, vt_test.proxy.ValidateToken("foobar")) +} + +func TestValidateTokenRequestNetworkFailure(t *testing.T) { + vt_test := NewValidateTokenTest() + // Close immediately to simulate a network failure + vt_test.Close() + + assert.Equal(t, false, vt_test.proxy.ValidateToken("foobar")) +} + +func TestValidateTokenExpiredToken(t *testing.T) { + vt_test := NewValidateTokenTest() + defer vt_test.Close() + + vt_test.response_code = 401 + assert.Equal(t, false, vt_test.proxy.ValidateToken("foobar")) +} + +func TestValidateTokenValidToken(t *testing.T) { + vt_test := NewValidateTokenTest() + defer vt_test.Close() + + assert.Equal(t, true, vt_test.proxy.ValidateToken("foobar")) +} + type ProcessCookieTest struct { opts *Options proxy *OauthProxy