git.iko.soy/typeable/oauth2-proxy
on master help sign in
Don't use http.StripPrefix when a file: upstream has rewriteTarget

A regular (non-regex) file: upstream needs to strip the prefix so that it is equivalent to "mounting" the specified directory under the configured path in the URL space, but with regex rewriting the target path is determined by the rewriteTarget. Fixes oauth2-proxy/oauth2-proxy#2242

commitcb53401c3af540942a2dc4b13744d28ccf9e88b6 authorIan Roberts <i.roberts@dcs.shef.ac.uk> dateThu 21 Sep 2023, 17:34 (3 years ago) parentb618ed7
3 files changed+47−7
pkg/upstream/file.go+39−5 pkg/upstream/file_test.go+7−1 pkg/upstream/proxy.go+1−1
pkg/upstream/file.go+39−5
@@ -2,9 +2,12 @@ package upstream
22
33import (
44 "net/http"
5+ "net/url"
56 "runtime"
67 "strings"
78
9+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
10+
811 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
912)
1013
@@ -12,22 +15,53 @@ const fileScheme = "file"
1215
1316// newFileServer creates a new fileServer that can serve requests
1417// to a file system location.
15−func newFileServer(id, path, fileSystemPath string) http.Handler {
18+func newFileServer(upstream options.Upstream, fileSystemPath string) http.Handler {
19+ handler := newFileServerForPath(fileSystemPath)
20+
21+ if upstream.RewriteTarget == "" {
22+ // if the upstream does not have a rewrite target, strip off the Path prefix
23+ // (so e.g. a request for /static/some-file.html looks for some-file.html
24+ // relative to the fileSystemPath rather than static/some-file.html).
25+ handler = http.StripPrefix(upstream.Path, handler)
26+ } else {
27+ // if the upstream *does* have a rewrite target then that means the target
28+ // path relative to the fileSystemPath will be the one in the (rewritten)
29+ // RequestURI.
30+ handler = requestURIToURL(handler)
31+ }
1632 return &fileServer{
17− upstream: id,
18− handler: newFileServerForPath(path, fileSystemPath),
33+ upstream: upstream.ID,
34+ handler: handler,
1935 }
2036}
2137
2238// newFileServerForPath creates a http.Handler to serve files from the filesystem
23−func newFileServerForPath(path string, filesystemPath string) http.Handler {
39+func newFileServerForPath(filesystemPath string) http.Handler {
2440 // Windows fileSSystemPath will be be prefixed with `/`, eg`/C:/...,
2541 // if they were parsed by url.Parse`
2642 if runtime.GOOS == "windows" {
2743 filesystemPath = strings.TrimPrefix(filesystemPath, "/")
2844 }
2945
30− return http.StripPrefix(path, http.FileServer(http.Dir(filesystemPath)))
46+ return http.FileServer(http.Dir(filesystemPath))
47+}
48+
49+// requestURIToURL returns a Handler that replaces the URL in its request with
50+// the result of parsing req.RequestURI. This is necessary for file handlers
51+// that have a rewrite target, since http.FileServer uses req.URL.Path when
52+// looking for the target file, but the rewrite handler only updates the
53+// RequestURI, leaving the original path in the URL.
54+func requestURIToURL(handler http.Handler) http.Handler {
55+ return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
56+ reqURL, err := url.ParseRequestURI(req.RequestURI)
57+ if err != nil {
58+ http.Error(rw, "500 Internal Server Error", http.StatusInternalServerError)
59+ return
60+ }
61+
62+ req.URL = reqURL
63+ handler.ServeHTTP(rw, req)
64+ })
3165}
3266
3367// fileServer represents a single filesystem upstream proxy
pkg/upstream/file_test.go+7−1
@@ -7,6 +7,8 @@ import (
77 "net/http/httptest"
88 "os"
99
10+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
11+
1012 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
1113 . "github.com/onsi/ginkgo/v2"
1214 . "github.com/onsi/gomega"
@@ -31,8 +33,12 @@ var _ = Describe("File Server Suite", func() {
3133 _, err := io.ReadFull(rand.Reader, idBytes)
3234 Expect(err).ToNot(HaveOccurred())
3335 id = string(idBytes)
36+ upstream := options.Upstream{
37+ ID: id,
38+ Path: "/files",
39+ }
3440
35− handler = newFileServer(id, "/files", filesDir)
41+ handler = newFileServer(upstream, filesDir)
3642 })
3743
3844 AfterEach(func() {
pkg/upstream/proxy.go+1−1
@@ -81,7 +81,7 @@ func (m *multiUpstreamProxy) registerStaticResponseHandler(upstream options.Upst
8181// registerFileServer registers a new fileServer based on the configuration given.
8282func (m *multiUpstreamProxy) registerFileServer(upstream options.Upstream, u *url.URL, writer pagewriter.Writer) error {
8383 logger.Printf("mapping path %q => file system %q", upstream.Path, u.Path)
84− return m.registerHandler(upstream, newFileServer(upstream.ID, upstream.Path, u.Path), writer)
84+ return m.registerHandler(upstream, newFileServer(upstream, u.Path), writer)
8585}
8686
8787// registerHTTPUpstreamProxy registers a new httpUpstreamProxy based on the configuration given.