10 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
11 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
12 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/app/pagewriter"
13 . "github.com/onsi/ginkgo"
14 . "github.com/onsi/ginkgo/extensions/table"
15 . "github.com/onsi/gomega"
18var _ = Describe("Proxy Suite", func() {
19 type proxyTableInput struct {
21 response testHTTPResponse
23 upstreams options.UpstreamConfig
26 Context("multiUpstreamProxy", func() {
27 DescribeTable("Proxy ServeHTTP",
28 func(in *proxyTableInput) {
29 sigData := &options.SignatureData{Hash: crypto.SHA256, Key: "secret"}
31 writer := &pagewriter.WriterFuncs{
32 ProxyErrorFunc: func(rw http.ResponseWriter, _ *http.Request, _ error) {
34 rw.Write([]byte("Proxy Error"))
39 accepted := http.StatusAccepted
41 // Allows for specifying settings and even individual upstreams for specific tests and uses the default upstreams/configs otherwise
42 upstreams := in.upstreams
43 if len(in.upstreams.Upstreams) == 0 {
44 upstreams.Upstreams = []options.Upstream{
53 URI: fmt.Sprintf("file:///%s", filesDir),
62 ID: "static-backend-no-trailing-slash",
65 StaticCode: &accepted,
68 ID: "static-backend-long",
71 StaticCode: &accepted,
74 ID: "bad-http-backend",
79 ID: "single-path-backend",
85 ID: "backend-with-rewrite-prefix",
86 Path: "^/rewrite-prefix/(.*)",
87 RewriteTarget: "/different/backend/path/$1",
91 ID: "double-match-plain",
92 Path: "/double-match/",
96 ID: "double-match-rewrite",
97 Path: "^/double-match/(.*)",
98 RewriteTarget: "/double-match/rewrite/$1",
104 upstreamServer, err := NewProxy(upstreams, sigData, writer)
105 Expect(err).ToNot(HaveOccurred())
107 req := middlewareapi.AddRequestScope(
108 httptest.NewRequest("", in.target, nil),
109 &middlewareapi.RequestScope{},
111 rw := httptest.NewRecorder()
112 // Don't mock the remote Address
115 upstreamServer.ServeHTTP(rw, req)
117 scope := middlewareapi.GetRequestScope(req)
118 Expect(scope.Upstream).To(Equal(in.upstream))
120 Expect(rw.Code).To(Equal(in.response.code))
122 // Delete extra headers that aren't relevant to tests
123 testSanitizeResponseHeader(rw.Header())
124 Expect(rw.Header()).To(Equal(in.response.header))
126 body := rw.Body.Bytes()
127 // If the raw body is set, check that, else check the Request object
128 if in.response.raw != "" {
129 Expect(string(body)).To(Equal(in.response.raw))
133 // Compare the reflected request to the upstream
135 request := testHTTPRequest{}
136 Expect(json.Unmarshal(body, &request)).To(Succeed())
137 testSanitizeRequestHeader(request.Header)
138 Expect(request).To(Equal(in.response.request))
141 Entry("with a request to the HTTP service", &proxyTableInput{
142 target: "http://example.localhost/http/1234",
143 response: testHTTPResponse{
145 header: map[string][]string{
146 contentType: {applicationJSON},
148 request: testHTTPRequest{
150 URL: "http://example.localhost/http/1234",
151 Header: map[string][]string{
153 "Gap-Signature": {"sha256 ofB1u6+FhEUbFLc3/uGbJVkl7GaN4egFqVvyO3+2I1w="},
156 Host: "example.localhost",
157 RequestURI: "http://example.localhost/http/1234",
160 upstream: "http-backend",
162 Entry("with a request to the File backend", &proxyTableInput{
163 target: "http://example.localhost/files/foo",
164 response: testHTTPResponse{
166 header: map[string][]string{
167 contentType: {textPlainUTF8},
171 upstream: "file-backend",
173 Entry("with a request to the Static backend", &proxyTableInput{
174 target: "http://example.localhost/static/bar",
175 response: testHTTPResponse{
177 header: map[string][]string{},
178 raw: "Authenticated",
180 upstream: "static-backend",
182 Entry("with a request to the bad HTTP backend", &proxyTableInput{
183 target: "http://example.localhost/bad-http/bad",
184 response: testHTTPResponse{
186 header: map[string][]string{},
187 // This tests the error handler
190 upstream: "bad-http-backend",
192 Entry("with a request to the to an unregistered path", &proxyTableInput{
193 target: "http://example.localhost/unregistered",
194 response: testHTTPResponse{
196 header: map[string][]string{
197 "X-Content-Type-Options": {"nosniff"},
198 contentType: {textPlainUTF8},
200 raw: "404 page not found\n",
203 Entry("with a request to the to backend registered to a single path", &proxyTableInput{
204 target: "http://example.localhost/single-path",
205 response: testHTTPResponse{
207 header: map[string][]string{},
208 raw: "Authenticated",
210 upstream: "single-path-backend",
212 Entry("with a request to the to a subpath of a backend registered to a single path", &proxyTableInput{
213 target: "http://example.localhost/single-path/unregistered",
214 response: testHTTPResponse{
216 header: map[string][]string{
217 "X-Content-Type-Options": {"nosniff"},
218 contentType: {textPlainUTF8},
220 raw: "404 page not found\n",
223 Entry("with a request to the rewrite prefix server", &proxyTableInput{
224 target: "http://example.localhost/rewrite-prefix/1234",
225 response: testHTTPResponse{
227 header: map[string][]string{
228 contentType: {applicationJSON},
230 request: testHTTPRequest{
232 URL: "http://example.localhost/different/backend/path/1234",
233 Header: map[string][]string{
235 "Gap-Signature": {"sha256 jeAeM7wHSj2ab/l9YPvtTJ9l/8q1tpY2V/iwXF48bgw="},
238 Host: "example.localhost",
239 RequestURI: "http://example.localhost/different/backend/path/1234",
242 upstream: "backend-with-rewrite-prefix",
244 Entry("with a request to a subpath of the rewrite prefix server", &proxyTableInput{
245 target: "http://example.localhost/rewrite-prefix/1234/abc",
246 response: testHTTPResponse{
248 header: map[string][]string{
249 contentType: {applicationJSON},
251 request: testHTTPRequest{
253 URL: "http://example.localhost/different/backend/path/1234/abc",
254 Header: map[string][]string{
256 "Gap-Signature": {"sha256 rAkAc9gp7EndoOppJuvbuPnYuBcqrTkBnQx6iPS8xTA="},
259 Host: "example.localhost",
260 RequestURI: "http://example.localhost/different/backend/path/1234/abc",
263 upstream: "backend-with-rewrite-prefix",
265 Entry("with a request to a path, missing the trailing slash", &proxyTableInput{
266 target: "http://example.localhost/http",
267 response: testHTTPResponse{
269 header: map[string][]string{
270 contentType: {textHTMLUTF8},
271 "Location": {"http://example.localhost/http/"},
273 raw: "<a href=\"http://example.localhost/http/\">Moved Permanently</a>.\n\n",
276 Entry("with a request to a path, missing the trailing slash, but registered separately", &proxyTableInput{
277 target: "http://example.localhost/static",
278 response: testHTTPResponse{
280 header: map[string][]string{},
281 raw: "Authenticated",
283 upstream: "static-backend-no-trailing-slash",
285 Entry("should match longest path first", &proxyTableInput{
286 target: "http://example.localhost/static/long",
287 response: testHTTPResponse{
289 header: map[string][]string{},
290 raw: "Authenticated",
292 upstream: "static-backend-long",
294 Entry("should match rewrite path first", &proxyTableInput{
295 target: "http://example.localhost/double-match/foo",
296 response: testHTTPResponse{
298 header: map[string][]string{
299 contentType: {applicationJSON},
301 request: testHTTPRequest{
303 URL: "http://example.localhost/double-match/rewrite/foo",
304 Header: map[string][]string{
306 "Gap-Signature": {"sha256 eYyUNdsrTmnvFpavpP8AdHGUGzqJ39QEjqn0/3fQPHA="},
309 Host: "example.localhost",
310 RequestURI: "http://example.localhost/double-match/rewrite/foo",
313 upstream: "double-match-rewrite",
315 Entry("containing an escaped '/' without ProxyRawPath", &proxyTableInput{
316 target: "http://example.localhost/%2F/test1/%2F/test2",
317 response: testHTTPResponse{
319 header: map[string][]string{
321 "http://example.localhost/test1/test2",
327 Entry("containing an escaped '/' with ProxyRawPath", &proxyTableInput{
328 upstreams: options.UpstreamConfig{ProxyRawPath: true},
329 target: "http://example.localhost/%2F/test1/%2F/test2",
330 response: testHTTPResponse{
332 header: map[string][]string{
333 "X-Content-Type-Options": {"nosniff"},
334 contentType: {textPlainUTF8},
336 raw: "404 page not found\n",
343 Context("sortByPathLongest", func() {
344 type sortByPathLongestTableInput struct {
345 input []options.Upstream
346 expectedOutput []options.Upstream
349 httpPath := options.Upstream{
353 httpSubPath := options.Upstream{
354 Path: "/http/subpath/",
357 longerPath := options.Upstream{
358 Path: "/longer-than-http",
361 shortPathWithRewrite := options.Upstream{
363 RewriteTarget: "/$1",
366 shortSubPathWithRewrite := options.Upstream{
367 Path: "^/h/bar/(.*)",
368 RewriteTarget: "/$1",
371 DescribeTable("short sort into the correct order",
372 func(in sortByPathLongestTableInput) {
373 Expect(sortByPathLongest(in.input)).To(Equal(in.expectedOutput))
375 Entry("with a mix of paths registered", sortByPathLongestTableInput{
376 input: []options.Upstream{httpPath, httpSubPath, shortSubPathWithRewrite, longerPath, shortPathWithRewrite},
377 expectedOutput: []options.Upstream{shortSubPathWithRewrite, shortPathWithRewrite, longerPath, httpSubPath, httpPath},
379 Entry("when a subpath is registered (in order)", sortByPathLongestTableInput{
380 input: []options.Upstream{httpSubPath, httpPath},
381 expectedOutput: []options.Upstream{httpSubPath, httpPath},
383 Entry("when a subpath is registered (out of order)", sortByPathLongestTableInput{
384 input: []options.Upstream{httpPath, httpSubPath},
385 expectedOutput: []options.Upstream{httpSubPath, httpPath},
387 Entry("when longer paths are registered (in order)", sortByPathLongestTableInput{
388 input: []options.Upstream{longerPath, httpPath},
389 expectedOutput: []options.Upstream{longerPath, httpPath},
391 Entry("when longer paths are registered (out of order)", sortByPathLongestTableInput{
392 input: []options.Upstream{httpPath, longerPath},
393 expectedOutput: []options.Upstream{longerPath, httpPath},
395 Entry("when a rewrite target is registered (in order)", sortByPathLongestTableInput{
396 input: []options.Upstream{shortPathWithRewrite, longerPath},
397 expectedOutput: []options.Upstream{shortPathWithRewrite, longerPath},
399 Entry("when a rewrite target is registered (out of order)", sortByPathLongestTableInput{
400 input: []options.Upstream{longerPath, shortPathWithRewrite},
401 expectedOutput: []options.Upstream{shortPathWithRewrite, longerPath},
403 Entry("with multiple rewrite targets registered (in order)", sortByPathLongestTableInput{
404 input: []options.Upstream{shortSubPathWithRewrite, shortPathWithRewrite},
405 expectedOutput: []options.Upstream{shortSubPathWithRewrite, shortPathWithRewrite},
407 Entry("with multiple rewrite targets registered (out of order)", sortByPathLongestTableInput{
408 input: []options.Upstream{shortPathWithRewrite, shortSubPathWithRewrite},
409 expectedOutput: []options.Upstream{shortSubPathWithRewrite, shortPathWithRewrite},
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