From ffeccfe5528b2574f2a60d57cd82f1ef6a328736 Mon Sep 17 00:00:00 2001 From: Jeppe Toustrup Date: Wed, 23 Sep 2015 22:00:36 +0200 Subject: [PATCH] Add support for serving static files from a directory The path should be provided as a file:// url with the full operating system path. An alias to where the directory is available as can be specified by appending a fragment (ie. "#/static/") at the end of the URL. --- README.md | 12 ++++++++++-- main.go | 2 +- oauthproxy.go | 31 +++++++++++++++++++++++-------- oauthproxy_test.go | 3 --- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 86cdc37..17c748d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ oauth2_proxy (This project was renamed from Google Auth Proxy - May 2015) -A reverse proxy that provides authentication using Providers (Google, Github, and others) +A reverse proxy and static file server that provides authentication using Providers (Google, Github, and others) to validate accounts by email, domain or group. [![Build Status](https://secure.travis-ci.org/bitly/oauth2_proxy.png?branch=master)](http://travis-ci.org/bitly/oauth2_proxy) @@ -152,13 +152,21 @@ Usage of oauth2_proxy: -skip-auth-regex=: bypass authentication for requests path's that match (may be given multiple times) -tls-cert="": path to certificate file -tls-key="": path to private key file - -upstream=: the http url(s) of the upstream endpoint. If multiple, routing is based on path + -upstream=: the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path -validate-url="": Access token validation endpoint -version=false: print version string ``` See below for provider specific options +### Upstreams Configuration + +`oauth2_proxy` supports having multiple upstreams, and has the option to pass requests on to HTTP(S) servers or serve static files from the file system. HTTP and HTTPS upstreams are configured by providing a URL such as `http://127.0.0.1:8080/` for the upstream parameter, that will forward all authenticated requests to be forwarded to the upstream server. If you instead provide `http://127.0.0.1:8080/some/path/` then it will only be requests that start with `/some/path/` which are forwarded to the upstream. + +Static file paths are configured as a file:// URL. `file:///var/www/static/` will serve the files from that directory at `http://[oauth2_proxy url]/var/www/static/`, which may not be what you want. You can provide the path to where the files should be available by adding a fragment to the configured URL. The value of the fragment will then be used to specify which path the files are available at. `file:///var/www/static/#/static/` will ie. make `/var/www/static/` available at `http://[oauth2_proxy url]/static/`. + +Multiple upstreams can either be configured by supplying a comma separated list to the `-upstream` parameter, supplying the parameter multiple times or provinding a list in the [config file](#config-file). When multiple upstreams are used routing to them will be based on the path they are set up with. + ### Environment variables The environment variables `OAUTH2_PROXY_CLIENT_ID`, `OAUTH2_PROXY_CLIENT_SECRET`, `OAUTH2_PROXY_COOKIE_SECRET`, `OAUTH2_PROXY_COOKIE_DOMAIN` and `OAUTH2_PROXY_COOKIE_EXPIRE` can be used in place of the corresponding command-line arguments. diff --git a/main.go b/main.go index 9c797b0..3fe3961 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ func main() { flagSet.String("tls-cert", "", "path to certificate file") flagSet.String("tls-key", "", "path to private key file") flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"") - flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint. If multiple, routing is based on path") + flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path") flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream") flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header") flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header") diff --git a/oauthproxy.go b/oauthproxy.go index 9d24542..739d9af 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -82,20 +82,35 @@ func setProxyDirector(proxy *httputil.ReverseProxy) { req.URL.RawQuery = "" } } +func NewFileServer(path string, filesystemPath string) (proxy http.Handler) { + return http.StripPrefix(path, http.FileServer(http.Dir(filesystemPath))) +} func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { serveMux := http.NewServeMux() for _, u := range opts.proxyUrls { path := u.Path - u.Path = "" - log.Printf("mapping path %q => upstream %q", path, u) - proxy := NewReverseProxy(u) - if !opts.PassHostHeader { - setProxyUpstreamHostHeader(proxy, u) - } else { - setProxyDirector(proxy) + switch u.Scheme { + case "http", "https": + u.Path = "" + log.Printf("mapping path %q => upstream %q", path, u) + proxy := NewReverseProxy(u) + if !opts.PassHostHeader { + setProxyUpstreamHostHeader(proxy, u) + } else { + setProxyDirector(proxy) + } + serveMux.Handle(path, &UpstreamProxy{u.Host, proxy}) + case "file": + if u.Fragment != "" { + path = u.Fragment + } + log.Printf("mapping path %q => file system %q", path, u.Path) + proxy := NewFileServer(path, u.Path) + serveMux.Handle(path, &UpstreamProxy{path, proxy}) + default: + panic(fmt.Sprintf("unknown upstream protocol %s", u.Scheme)) } - serveMux.Handle(path, &UpstreamProxy{u.Host, proxy}) } for _, u := range opts.CompiledRegex { log.Printf("compiled skip-auth-regex => %q", u) diff --git a/oauthproxy_test.go b/oauthproxy_test.go index 52b48bb..ca0b9c4 100644 --- a/oauthproxy_test.go +++ b/oauthproxy_test.go @@ -75,7 +75,6 @@ func TestEncodedSlashes(t *testing.T) { func TestRobotsTxt(t *testing.T) { opts := NewOptions() - opts.Upstreams = append(opts.Upstreams, "unused") opts.ClientID = "bazquux" opts.ClientSecret = "foobar" opts.CookieSecret = "xyzzyplugh" @@ -371,7 +370,6 @@ func NewSignInPageTest() *SignInPageTest { var sip_test SignInPageTest sip_test.opts = NewOptions() - sip_test.opts.Upstreams = append(sip_test.opts.Upstreams, "unused") sip_test.opts.CookieSecret = "foobar" sip_test.opts.ClientID = "bazquux" sip_test.opts.ClientSecret = "xyzzyplugh" @@ -443,7 +441,6 @@ func NewProcessCookieTest(opts ProcessCookieTestOpts) *ProcessCookieTest { var pc_test ProcessCookieTest pc_test.opts = NewOptions() - pc_test.opts.Upstreams = append(pc_test.opts.Upstreams, "unused") pc_test.opts.ClientID = "bazquux" pc_test.opts.ClientSecret = "xyzzyplugh" pc_test.opts.CookieSecret = "0123456789abcdef"