@@ -0,0 +1,177 @@
1+package redirect
2+
3+import (
4+ "net/http"
5+
6+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
7+ . "github.com/onsi/ginkgo"
8+ . "github.com/onsi/ginkgo/extensions/table"
9+ . "github.com/onsi/gomega"
10+)
11+
12+const testProxyPrefix = "/oauth2"
13+
14+var _ = Describe("Director Suite", func() {
15+ type getRedirectTableInput struct {
16+ requestURL string
17+ headers map[string]string
18+ reverseProxy bool
19+ validator Validator
20+ expectedRedirect string
21+ }
22+
23+ DescribeTable("GetRedirect",
24+ func(in getRedirectTableInput) {
25+ appDirector := NewAppDirector(AppDirectorOpts{
26+ ProxyPrefix: testProxyPrefix,
27+ Validator: in.validator,
28+ })
29+
30+ req, _ := http.NewRequest("GET", in.requestURL, nil)
31+ for header, value := range in.headers {
32+ if value != "" {
33+ req.Header.Add(header, value)
34+ }
35+ }
36+ req = middleware.AddRequestScope(req, &middleware.RequestScope{
37+ ReverseProxy: in.reverseProxy,
38+ })
39+
40+ redirect, err := appDirector.GetRedirect(req)
41+ Expect(err).ToNot(HaveOccurred())
42+ Expect(redirect).To(Equal(in.expectedRedirect))
43+ },
44+ Entry("Request outside of the proxy prefix, redirects to original request", getRedirectTableInput{
45+ requestURL: "/foo/bar",
46+ headers: nil,
47+ reverseProxy: false,
48+ validator: testValidator(true),
49+ expectedRedirect: "/foo/bar",
50+ }),
51+ Entry("Request with query, preserves the query", getRedirectTableInput{
52+ requestURL: "/foo?bar",
53+ headers: nil,
54+ reverseProxy: false,
55+ validator: testValidator(true),
56+ expectedRedirect: "/foo?bar",
57+ }),
58+ Entry("Request under the proxy prefix, redirects to root", getRedirectTableInput{
59+ requestURL: testProxyPrefix + "/foo/bar",
60+ headers: nil,
61+ reverseProxy: false,
62+ validator: testValidator(true),
63+ expectedRedirect: "/",
64+ }),
65+ Entry("Proxied request with headers, outside of ProxyPrefix, redirects to proxied URL", getRedirectTableInput{
66+ requestURL: "https://oauth.example.com/foo/bar",
67+ headers: map[string]string{
68+ "X-Forwarded-Proto": "https",
69+ "X-Forwarded-Host": "a-service.example.com",
70+ "X-Forwarded-Uri": "/foo/bar",
71+ },
72+ reverseProxy: true,
73+ validator: testValidator(true),
74+ expectedRedirect: "https://a-service.example.com/foo/bar",
75+ }),
76+ Entry("Non-proxied request with spoofed headers, wouldn't redirect", getRedirectTableInput{
77+ requestURL: "https://oauth.example.com/foo?bar",
78+ headers: map[string]string{
79+ "X-Forwarded-Proto": "https",
80+ "X-Forwarded-Host": "a-service.example.com",
81+ "X-Forwarded-Uri": "/foo/bar",
82+ },
83+ reverseProxy: false,
84+ validator: testValidator(true),
85+ expectedRedirect: "/foo?bar",
86+ }),
87+ Entry("Proxied request with headers, under ProxyPrefix, redirects to root", getRedirectTableInput{
88+ requestURL: "https://oauth.example.com" + testProxyPrefix + "/foo/bar",
89+ headers: map[string]string{
90+ "X-Forwarded-Proto": "https",
91+ "X-Forwarded-Host": "a-service.example.com",
92+ "X-Forwarded-Uri": testProxyPrefix + "/foo/bar",
93+ },
94+ reverseProxy: true,
95+ validator: testValidator(true),
96+ expectedRedirect: "https://a-service.example.com/",
97+ }),
98+ Entry("Proxied request with port, under ProxyPrefix, redirects to root", getRedirectTableInput{
99+ requestURL: "https://oauth.example.com" + testProxyPrefix + "/foo/bar",
100+ headers: map[string]string{
101+ "X-Forwarded-Proto": "https",
102+ "X-Forwarded-Host": "a-service.example.com:8443",
103+ "X-Forwarded-Uri": testProxyPrefix + "/foo/bar",
104+ },
105+ reverseProxy: true,
106+ validator: testValidator(true),
107+ expectedRedirect: "https://a-service.example.com:8443/",
108+ }),
109+ Entry("Proxied request with headers, missing URI header, redirects to the desired redirect URL", getRedirectTableInput{
110+ requestURL: "https://oauth.example.com/foo?bar",
111+ headers: map[string]string{
112+ "X-Forwarded-Proto": "https",
113+ "X-Forwarded-Host": "a-service.example.com",
114+ },
115+ reverseProxy: true,
116+ validator: testValidator(true),
117+ expectedRedirect: "https://a-service.example.com/foo?bar",
118+ }),
119+ Entry("Proxied request without headers, with reverse proxy enabled, redirects to the desired URL", getRedirectTableInput{
120+ requestURL: "https://oauth.example.com/foo?bar",
121+ headers: nil,
122+ reverseProxy: true,
123+ validator: testValidator(true),
124+ expectedRedirect: "/foo?bar",
125+ }),
126+ Entry("Proxied request with X-Auth-Request-Redirect, outside of ProxyPrefix, redirects to proxied URL", getRedirectTableInput{
127+ requestURL: "https://oauth.example.com/foo/bar",
128+ headers: map[string]string{
129+ "X-Auth-Request-Redirect": "https://a-service.example.com/foo/bar",
130+ },
131+ reverseProxy: true,
132+ validator: testValidator(true),
133+ expectedRedirect: "https://a-service.example.com/foo/bar",
134+ }),
135+ Entry("Proxied request with RD parameter, outside of ProxyPrefix, redirects to proxied URL", getRedirectTableInput{
136+ requestURL: "https://oauth.example.com/foo/bar?rd=https%3A%2F%2Fa%2Dservice%2Eexample%2Ecom%2Ffoo%2Fbar",
137+ headers: nil,
138+ reverseProxy: false,
139+ validator: testValidator(true),
140+ expectedRedirect: "https://a-service.example.com/foo/bar",
141+ }),
142+ Entry("Proxied request with RD parameter and all headers set, reverse proxy disabled, redirects to proxied URL based on the RD parameter", getRedirectTableInput{
143+ requestURL: "https://oauth.example.com/foo/bar?rd=https%3A%2F%2Fa%2Dservice%2Eexample%2Ecom%2Ffoo%2Fjazz",
144+ headers: map[string]string{
145+ "X-Auth-Request-Redirect": "https://a-service.example.com/foo/baz",
146+ "X-Forwarded-Proto": "http",
147+ "X-Forwarded-Host": "another-service.example.com",
148+ "X-Forwarded-Uri": "/seasons/greetings",
149+ },
150+ reverseProxy: false,
151+ validator: testValidator(true),
152+ expectedRedirect: "https://a-service.example.com/foo/jazz",
153+ }),
154+ Entry("Proxied request with RD parameter and some headers set, reverse proxy enabled, redirects to proxied URL based on the RD parameter", getRedirectTableInput{
155+ requestURL: "https://oauth.example.com/foo/bar?rd=https%3A%2F%2Fa%2Dservice%2Eexample%2Ecom%2Ffoo%2Fjazz",
156+ headers: map[string]string{
157+ "X-Forwarded-Proto": "http",
158+ "X-Forwarded-Host": "another-service.example.com",
159+ "X-Forwarded-Uri": "/seasons/greetings",
160+ },
161+ reverseProxy: true,
162+ validator: testValidator(true),
163+ expectedRedirect: "https://a-service.example.com/foo/jazz",
164+ }),
165+ Entry("Proxied request with invalid RD parameter and some headers set, reverse proxy enabled, redirects to proxied URL based on the headers", getRedirectTableInput{
166+ requestURL: "https://oauth.example.com/foo/bar?rd=http%3A%2F%2Fanother%2Dservice%2Eexample%2Ecom%2Ffoo%2Fjazz",
167+ headers: map[string]string{
168+ "X-Forwarded-Proto": "https",
169+ "X-Forwarded-Host": "a-service.example.com",
170+ "X-Forwarded-Uri": "/foo/bar",
171+ },
172+ reverseProxy: true,
173+ validator: testValidator(false, "https://a-service.example.com/foo/bar"),
174+ expectedRedirect: "https://a-service.example.com/foo/bar",
175+ }),
176+ )
177+})