git.iko.soy/typeable/oauth2-proxy
on ea261ca help sign in
438 lines 11 kB history raw
1package middleware
3import (
4 "encoding/base64"
5 "net/http"
6 "net/http/httptest"
8 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
9 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
10 sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
11 . "github.com/onsi/ginkgo"
12 . "github.com/onsi/ginkgo/extensions/table"
13 . "github.com/onsi/gomega"
16var _ = Describe("Headers Suite", func() {
17 type headersTableInput struct {
18 headers []options.Header
19 initialHeaders http.Header
20 session *sessionsapi.SessionState
21 expectedHeaders http.Header
22 expectedErr string
23 }
25 DescribeTable("the request header injector",
26 func(in headersTableInput) {
27 scope := &middlewareapi.RequestScope{
28 Session: in.session,
29 }
31 // Set up the request with a request scope
32 req := httptest.NewRequest("", "/", nil)
33 req = middlewareapi.AddRequestScope(req, scope)
34 req.Header = in.initialHeaders.Clone()
36 rw := httptest.NewRecorder()
38 // Create the handler with a next handler that will capture the headers
39 // from the request
40 var gotHeaders http.Header
41 injector, err := NewRequestHeaderInjector(in.headers)
42 if in.expectedErr != "" {
43 Expect(err).To(MatchError(in.expectedErr))
44 return
45 }
46 Expect(err).ToNot(HaveOccurred())
48 handler := injector(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
49 gotHeaders = r.Header.Clone()
50 }))
51 handler.ServeHTTP(rw, req)
53 Expect(gotHeaders).To(Equal(in.expectedHeaders))
54 },
55 Entry("with no configured headers", headersTableInput{
56 headers: []options.Header{},
57 initialHeaders: http.Header{
58 "Foo": []string{"bar", "baz"},
59 },
60 session: &sessionsapi.SessionState{},
61 expectedHeaders: http.Header{
62 "Foo": []string{"bar,baz"},
63 },
64 expectedErr: "",
65 }),
66 Entry("with a claim valued header", headersTableInput{
67 headers: []options.Header{
68 {
69 Name: "Claim",
70 Values: []options.HeaderValue{
71 {
72 ClaimSource: &options.ClaimSource{
73 Claim: "id_token",
74 },
75 },
76 },
77 },
78 },
79 initialHeaders: http.Header{
80 "Foo": []string{"bar", "baz"},
81 },
82 session: &sessionsapi.SessionState{
83 IDToken: "IDToken-1234",
84 },
85 expectedHeaders: http.Header{
86 "Foo": []string{"bar,baz"},
87 "Claim": []string{"IDToken-1234"},
88 },
89 expectedErr: "",
90 }),
91 Entry("with a claim valued header (without preservation)", headersTableInput{
92 headers: []options.Header{
93 {
94 Name: "Claim",
95 Values: []options.HeaderValue{
96 {
97 ClaimSource: &options.ClaimSource{
98 Claim: "id_token",
99 },
100 },
101 },
102 },
103 },
104 initialHeaders: http.Header{
105 "Claim": []string{"bar", "baz"},
106 },
107 session: &sessionsapi.SessionState{
108 IDToken: "IDToken-1234",
109 },
110 expectedHeaders: http.Header{
111 "Claim": []string{"IDToken-1234"},
112 },
113 expectedErr: "",
114 }),
115 Entry("with a claim valued header (with preservation)", headersTableInput{
116 headers: []options.Header{
117 {
118 Name: "Claim",
119 PreserveRequestValue: true,
120 Values: []options.HeaderValue{
121 {
122 ClaimSource: &options.ClaimSource{
123 Claim: "id_token",
124 },
125 },
126 },
127 },
128 },
129 initialHeaders: http.Header{
130 "Claim": []string{"bar", "baz"},
131 },
132 session: &sessionsapi.SessionState{
133 IDToken: "IDToken-1234",
134 },
135 expectedHeaders: http.Header{
136 "Claim": []string{"bar,baz,IDToken-1234"},
137 },
138 expectedErr: "",
139 }),
140 Entry("with a claim valued header that's not present (without preservation)", headersTableInput{
141 headers: []options.Header{
142 {
143 Name: "Claim",
144 Values: []options.HeaderValue{
145 {
146 ClaimSource: &options.ClaimSource{
147 Claim: "id_token",
148 },
149 },
150 },
151 },
152 },
153 initialHeaders: http.Header{
154 "Claim": []string{"bar", "baz"},
155 },
156 session: nil,
157 expectedHeaders: http.Header{},
158 expectedErr: "",
159 }),
160 Entry("with a claim valued header that's not present (with preservation)", headersTableInput{
161 headers: []options.Header{
162 {
163 Name: "Claim",
164 PreserveRequestValue: true,
165 Values: []options.HeaderValue{
166 {
167 ClaimSource: &options.ClaimSource{
168 Claim: "id_token",
169 },
170 },
171 },
172 },
173 },
174 initialHeaders: http.Header{
175 "Claim": []string{"bar", "baz"},
176 },
177 session: nil,
178 expectedHeaders: http.Header{
179 "Claim": []string{"bar,baz"},
180 },
181 expectedErr: "",
182 }),
183 Entry("with an invalid basicAuthPassword claim valued header", headersTableInput{
184 headers: []options.Header{
185 {
186 Name: "X-Auth-Request-Authorization",
187 Values: []options.HeaderValue{
188 {
189 ClaimSource: &options.ClaimSource{
190 Claim: "user",
191 BasicAuthPassword: &options.SecretSource{
192 Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))),
193 FromEnv: "SECRET_ENV",
194 },
195 },
196 },
197 },
198 },
199 },
200 initialHeaders: http.Header{
201 "foo": []string{"bar", "baz"},
202 },
203 session: &sessionsapi.SessionState{
204 User: "user-123",
205 },
206 expectedHeaders: nil,
207 expectedErr: "error building request header injector: error building request injector: error building injector for header \"X-Auth-Request-Authorization\": error loading basicAuthPassword: secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile",
208 }),
209 )
211 DescribeTable("the response header injector",
212 func(in headersTableInput) {
213 scope := &middlewareapi.RequestScope{
214 Session: in.session,
215 }
217 // Set up the request with a request scope
218 req := httptest.NewRequest("", "/", nil)
219 req = middlewareapi.AddRequestScope(req, scope)
221 rw := httptest.NewRecorder()
222 for key, values := range in.initialHeaders {
223 for _, value := range values {
224 rw.Header().Add(key, value)
225 }
226 }
228 // Create the handler with a next handler that will capture the headers
229 // from the request
230 var gotHeaders http.Header
231 injector, err := NewResponseHeaderInjector(in.headers)
232 if in.expectedErr != "" {
233 Expect(err).To(MatchError(in.expectedErr))
234 return
235 }
236 Expect(err).ToNot(HaveOccurred())
238 handler := injector(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
239 gotHeaders = w.Header().Clone()
240 }))
241 handler.ServeHTTP(rw, req)
243 Expect(gotHeaders).To(Equal(in.expectedHeaders))
244 },
245 Entry("with no configured headers", headersTableInput{
246 headers: []options.Header{},
247 initialHeaders: http.Header{
248 "Foo": []string{"bar", "baz"},
249 },
250 session: &sessionsapi.SessionState{},
251 expectedHeaders: http.Header{
252 "Foo": []string{"bar,baz"},
253 },
254 expectedErr: "",
255 }),
257 Entry("with flattenHeaders (set-cookie and any other)", headersTableInput{
258 headers: []options.Header{
259 {
260 Name: "Set-Cookie",
261 Values: []options.HeaderValue{
262 {
263 SecretSource: &options.SecretSource{
264 Value: []byte("_oauth2_proxy=ey123123123"),
265 },
266 },
267 },
268 },
269 {
270 Name: "X-Auth-User",
271 Values: []options.HeaderValue{
272 {
273 SecretSource: &options.SecretSource{
274 Value: []byte("oauth_user"),
275 },
276 },
277 },
278 },
279 },
280 initialHeaders: http.Header{
281 "Set-Cookie": []string{"cookie1=value1", "cookie2=value2"},
282 "X-Auth-User": []string{"oauth_user_1"},
283 },
285 expectedHeaders: http.Header{
286 "Set-Cookie": []string{"cookie1=value1", "cookie2=value2", "_oauth2_proxy=ey123123123"},
287 "X-Auth-User": []string{"oauth_user_1,oauth_user"},
288 },
289 expectedErr: "",
290 }),
292 Entry("with a claim valued header", headersTableInput{
293 headers: []options.Header{
294 {
295 Name: "Claim",
296 Values: []options.HeaderValue{
297 {
298 ClaimSource: &options.ClaimSource{
299 Claim: "id_token",
300 },
301 },
302 },
303 },
304 },
305 initialHeaders: http.Header{
306 "Foo": []string{"bar", "baz"},
307 },
308 session: &sessionsapi.SessionState{
309 IDToken: "IDToken-1234",
310 },
311 expectedHeaders: http.Header{
312 "Foo": []string{"bar,baz"},
313 "Claim": []string{"IDToken-1234"},
314 },
315 expectedErr: "",
316 }),
317 Entry("with a claim valued header (without preservation)", headersTableInput{
318 headers: []options.Header{
319 {
320 Name: "Claim",
321 Values: []options.HeaderValue{
322 {
323 ClaimSource: &options.ClaimSource{
324 Claim: "id_token",
325 },
326 },
327 },
328 },
329 },
330 initialHeaders: http.Header{
331 "Claim": []string{"bar", "baz"},
332 },
333 session: &sessionsapi.SessionState{
334 IDToken: "IDToken-1234",
335 },
336 expectedHeaders: http.Header{
337 "Claim": []string{"bar,baz,IDToken-1234"},
338 },
339 expectedErr: "",
340 }),
341 Entry("with a claim valued header (with preservation)", headersTableInput{
342 headers: []options.Header{
343 {
344 Name: "Claim",
345 PreserveRequestValue: true,
346 Values: []options.HeaderValue{
347 {
348 ClaimSource: &options.ClaimSource{
349 Claim: "id_token",
350 },
351 },
352 },
353 },
354 },
355 initialHeaders: http.Header{
356 "Claim": []string{"bar", "baz"},
357 },
358 session: &sessionsapi.SessionState{
359 IDToken: "IDToken-1234",
360 },
361 expectedHeaders: http.Header{
362 "Claim": []string{"bar,baz,IDToken-1234"},
363 },
364 expectedErr: "",
365 }),
366 Entry("with a claim valued header that's not present (without preservation)", headersTableInput{
367 headers: []options.Header{
368 {
369 Name: "Claim",
370 Values: []options.HeaderValue{
371 {
372 ClaimSource: &options.ClaimSource{
373 Claim: "id_token",
374 },
375 },
376 },
377 },
378 },
379 initialHeaders: http.Header{
380 "Claim": []string{"bar", "baz"},
381 },
382 session: nil,
383 expectedHeaders: http.Header{
384 "Claim": []string{"bar,baz"},
385 },
386 expectedErr: "",
387 }),
388 Entry("with a claim valued header that's not present (with preservation)", headersTableInput{
389 headers: []options.Header{
390 {
391 Name: "Claim",
392 PreserveRequestValue: true,
393 Values: []options.HeaderValue{
394 {
395 ClaimSource: &options.ClaimSource{
396 Claim: "id_token",
397 },
398 },
399 },
400 },
401 },
402 initialHeaders: http.Header{
403 "Claim": []string{"bar", "baz"},
404 },
405 session: nil,
406 expectedHeaders: http.Header{
407 "Claim": []string{"bar,baz"},
408 },
409 expectedErr: "",
410 }),
411 Entry("with an invalid basicAuthPassword claim valued header", headersTableInput{
412 headers: []options.Header{
413 {
414 Name: "X-Auth-Request-Authorization",
415 Values: []options.HeaderValue{
416 {
417 ClaimSource: &options.ClaimSource{
418 Claim: "user",
419 BasicAuthPassword: &options.SecretSource{
420 Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))),
421 FromEnv: "SECRET_ENV",
422 },
423 },
424 },
425 },
426 },
427 },
428 initialHeaders: http.Header{
429 "foo": []string{"bar", "baz"},
430 },
431 session: &sessionsapi.SessionState{
432 User: "user-123",
433 },
434 expectedHeaders: nil,
435 expectedErr: "error building response header injector: error building response injector: error building injector for header \"X-Auth-Request-Authorization\": error loading basicAuthPassword: secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile",
436 }),
437 )
438})