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