git.iko.soy/typeable/oauth2-proxy
on master help sign in
Merge pull request #265 from cgroschupp/feat/static-upstream

Add upstream with static response

commit68abf7b2d82e6bedd03673aba55aad263649de76 authorJoel Speed <Joel.speed@hotmail.co.uk> dateTue 19 Nov 2019, 15:01 (7 years ago) parent5c9a0f86d74a42
5 files changed+49−7
CHANGELOG.md+1 docs/configuration/configuration.md+1−1 main.go+1−1 oauthproxy.go+12 oauthproxy_test.go+34−5
CHANGELOG.md+1
@@ -15,6 +15,7 @@
1515- [#300](https://github.com/pusher/oauth2_proxy/pull/300) Added userinfo endpoint (@kbabuadze)
1616- [#309](https://github.com/pusher/oauth2_proxy/pull/309) Added support for custom CA when connecting to Redis cache (@lleszczu)
1717- [#248](https://github.com/pusher/oauth2_proxy/pull/248) Fix issue with X-Auth-Request-Redirect header being ignored (@webnard)
18+- [#265](https://github.com/pusher/oauth2_proxy/pull/265) Add upstream with static response (@cgroschupp)
1819
1920# v4.0.0
2021
docs/configuration/configuration.md+1−1
@@ -106,7 +106,7 @@ An example [oauth2_proxy.cfg]({{ site.gitweb }}/contrib/oauth2_proxy.cfg.example
106106| `-standard-logging-format` | string | Template for standard log lines | see [Logging Configuration](#logging-configuration) |
107107| `-tls-cert-file` | string | path to certificate file | |
108108| `-tls-key-file` | string | path to private key file | |
109−| `-upstream` | string \| list | the http url(s) of the upstream endpoint or `file://` paths for static files. Routing is based on the path | |
109+| `-upstream` | string \| list | the http url(s) of the upstream endpoint, file:// paths for static files or `static://<status_code>` for static response. Routing is based on the path | |
110110| `-validate-url` | string | Access token validation endpoint | |
111111| `-version` | n/a | print version string | |
112112| `-whitelist-domain` | string \| list | allowed domains for redirection after authentication. Prefix domain with a `.` to allow subdomains (eg `.example.com`) | |
main.go+1−1
@@ -37,7 +37,7 @@ func main() {
3737 flagSet.String("tls-key-file", "", "path to private key file")
3838 flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"")
3939 flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)")
40− flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path")
40+ flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint, file:// paths for static files or static://<status_code> for static response. Routing is based on the path")
4141 flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
4242 flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream")
4343 flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
oauthproxy.go+12
@@ -13,6 +13,7 @@ import (
1313 "net/http/httputil"
1414 "net/url"
1515 "regexp"
16+ "strconv"
1617 "strings"
1718 "time"
1819
@@ -203,12 +204,23 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
203204 }
204205 for _, u := range opts.proxyURLs {
205206 path := u.Path
207+ host := u.Host
206208 switch u.Scheme {
207209 case httpScheme, httpsScheme:
208210 logger.Printf("mapping path %q => upstream %q", path, u)
209211 proxy := NewWebSocketOrRestReverseProxy(u, opts, auth)
210212 serveMux.Handle(path, proxy)
213+ case "static":
214+ responseCode, err := strconv.Atoi(host)
215+ if err != nil {
216+ logger.Printf("unable to convert %q to int, use default \"200\"", host)
217+ responseCode = 200
218+ }
211219
220+ serveMux.HandleFunc(path, func(rw http.ResponseWriter, req *http.Request) {
221+ rw.WriteHeader(responseCode)
222+ fmt.Fprintf(rw, "Authenticated")
223+ })
212224 case "file":
213225 if u.Fragment != "" {
214226 path = u.Fragment
oauthproxy_test.go+34−5
@@ -365,6 +365,7 @@ type PassAccessTokenTest struct {
365365
366366type PassAccessTokenTestOptions struct {
367367 PassAccessToken bool
368+ ProxyUpstream string
368369}
369370
370371func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTest {
@@ -372,7 +373,6 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTes
372373
373374 t.providerServer = httptest.NewServer(
374375 http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
375− logger.Printf("%#v", r)
376376 var payload string
377377 switch r.URL.Path {
378378 case "/oauth/token":
@@ -389,6 +389,9 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTes
389389
390390 t.opts = NewOptions()
391391 t.opts.Upstreams = append(t.opts.Upstreams, t.providerServer.URL)
392+ if opts.ProxyUpstream != "" {
393+ t.opts.Upstreams = append(t.opts.Upstreams, opts.ProxyUpstream)
394+ }
392395 // The CookieSecret must be 32 bytes in order to create the AES
393396 // cipher.
394397 t.opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
@@ -425,7 +428,9 @@ func (patTest *PassAccessTokenTest) getCallbackEndpoint() (httpCode int,
425428 return rw.Code, rw.HeaderMap["Set-Cookie"][1]
426429}
427430
428−func (patTest *PassAccessTokenTest) getRootEndpoint(cookie string) (httpCode int, accessToken string) {
431+// getEndpointWithCookie makes a requests againt the oauthproxy with passed requestPath
432+// and cookie and returns body and status code.
433+func (patTest *PassAccessTokenTest) getEndpointWithCookie(cookie string, endpoint string) (httpCode int, accessToken string) {
429434 cookieName := patTest.proxy.CookieName
430435 var value string
431436 keyPrefix := cookieName + "="
@@ -442,7 +447,7 @@ func (patTest *PassAccessTokenTest) getRootEndpoint(cookie string) (httpCode int
442447 return 0, ""
443448 }
444449
445− req, err := http.NewRequest("GET", "/", strings.NewReader(""))
450+ req, err := http.NewRequest("GET", endpoint, strings.NewReader(""))
446451 if err != nil {
447452 return 0, ""
448453 }
@@ -475,13 +480,37 @@ func TestForwardAccessTokenUpstream(t *testing.T) {
475480 // Now we make a regular request; the access_token from the cookie is
476481 // forwarded as the "X-Forwarded-Access-Token" header. The token is
477482 // read by the test provider server and written in the response body.
478− code, payload := patTest.getRootEndpoint(cookie)
483+ code, payload := patTest.getEndpointWithCookie(cookie, "/")
479484 if code != 200 {
480485 t.Fatalf("expected 200; got %d", code)
481486 }
482487 assert.Equal(t, "my_auth_token", payload)
483488}
484489
490+func TestStaticProxyUpstream(t *testing.T) {
491+ patTest := NewPassAccessTokenTest(PassAccessTokenTestOptions{
492+ PassAccessToken: true,
493+ ProxyUpstream: "static://200/static-proxy",
494+ })
495+
496+ defer patTest.Close()
497+
498+ // A successful validation will redirect and set the auth cookie.
499+ code, cookie := patTest.getCallbackEndpoint()
500+ if code != 302 {
501+ t.Fatalf("expected 302; got %d", code)
502+ }
503+ assert.NotEqual(t, nil, cookie)
504+
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")
508+ if code != 200 {
509+ t.Fatalf("expected 200; got %d", code)
510+ }
511+ assert.Equal(t, "Authenticated", payload)
512+}
513+
485514func TestDoNotForwardAccessTokenUpstream(t *testing.T) {
486515 patTest := NewPassAccessTokenTest(PassAccessTokenTestOptions{
487516 PassAccessToken: false,
@@ -497,7 +526,7 @@ func TestDoNotForwardAccessTokenUpstream(t *testing.T) {
497526
498527 // Now we make a regular request, but the access token header should
499528 // not be present.
500− code, payload := patTest.getRootEndpoint(cookie)
529+ code, payload := patTest.getEndpointWithCookie(cookie, "/")
501530 if code != 200 {
502531 t.Fatalf("expected 200; got %d", code)
503532 }