git.iko.soy/typeable/oauth2-proxy
on f8ddc13 help sign in
500 lines 14 kB history raw
1package http
3import (
4 "context"
5 "errors"
6 "fmt"
7 "io/ioutil"
8 "net/http"
10 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
11 . "github.com/onsi/ginkgo"
12 . "github.com/onsi/ginkgo/extensions/table"
13 . "github.com/onsi/gomega"
16const hello = "Hello World!"
18var _ = Describe("Server", func() {
19 handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
20 rw.Write([]byte(hello))
21 })
23 Context("NewServer", func() {
24 type newServerTableInput struct {
25 opts Opts
26 expectedErr error
27 expectHTTPListener bool
28 expectTLSListener bool
29 }
31 DescribeTable("When creating the new server from the options", func(in *newServerTableInput) {
32 srv, err := NewServer(in.opts)
33 if in.expectedErr != nil {
34 Expect(err).To(MatchError(ContainSubstring(in.expectedErr.Error())))
35 Expect(srv).To(BeNil())
36 return
37 }
39 Expect(err).ToNot(HaveOccurred())
41 s, ok := srv.(*server)
42 Expect(ok).To(BeTrue())
44 Expect(s.listener != nil).To(Equal(in.expectHTTPListener))
45 if in.expectHTTPListener {
46 Expect(s.listener.Close()).To(Succeed())
47 }
48 Expect(s.tlsListener != nil).To(Equal(in.expectTLSListener))
49 if in.expectTLSListener {
50 Expect(s.tlsListener.Close()).To(Succeed())
51 }
52 },
53 Entry("with a valid http bind address", &newServerTableInput{
54 opts: Opts{
55 Handler: handler,
56 BindAddress: "127.0.0.1:0",
57 },
58 expectedErr: nil,
59 expectHTTPListener: true,
60 expectTLSListener: false,
61 }),
62 Entry("with a valid https bind address, with no TLS config", &newServerTableInput{
63 opts: Opts{
64 Handler: handler,
65 SecureBindAddress: "127.0.0.1:0",
66 },
67 expectedErr: errors.New("error setting up TLS listener: no TLS config provided"),
68 expectHTTPListener: false,
69 expectTLSListener: false,
70 }),
71 Entry("with a valid https bind address, and valid TLS config", &newServerTableInput{
72 opts: Opts{
73 Handler: handler,
74 SecureBindAddress: "127.0.0.1:0",
75 TLS: &options.TLS{
76 Key: &keyDataSource,
77 Cert: &certDataSource,
78 },
79 },
80 expectedErr: nil,
81 expectHTTPListener: false,
82 expectTLSListener: true,
83 }),
84 Entry("with a both a valid http and valid https bind address, and valid TLS config", &newServerTableInput{
85 opts: Opts{
86 Handler: handler,
87 BindAddress: "127.0.0.1:0",
88 SecureBindAddress: "127.0.0.1:0",
89 TLS: &options.TLS{
90 Key: &keyDataSource,
91 Cert: &certDataSource,
92 },
93 },
94 expectedErr: nil,
95 expectHTTPListener: true,
96 expectTLSListener: true,
97 }),
98 Entry("with a \"-\" for the bind address", &newServerTableInput{
99 opts: Opts{
100 Handler: handler,
101 BindAddress: "-",
102 },
103 expectedErr: nil,
104 expectHTTPListener: false,
105 expectTLSListener: false,
106 }),
107 Entry("with a \"-\" for the secure bind address", &newServerTableInput{
108 opts: Opts{
109 Handler: handler,
110 SecureBindAddress: "-",
111 },
112 expectedErr: nil,
113 expectHTTPListener: false,
114 expectTLSListener: false,
115 }),
116 Entry("with an invalid bind address scheme", &newServerTableInput{
117 opts: Opts{
118 Handler: handler,
119 BindAddress: "invalid://127.0.0.1:0",
120 },
121 expectedErr: errors.New("error setting up listener: listen (invalid, 127.0.0.1:0) failed: listen invalid: unknown network invalid"),
122 expectHTTPListener: false,
123 expectTLSListener: false,
124 }),
125 Entry("with an invalid secure bind address scheme", &newServerTableInput{
126 opts: Opts{
127 Handler: handler,
128 SecureBindAddress: "invalid://127.0.0.1:0",
129 TLS: &options.TLS{
130 Key: &keyDataSource,
131 Cert: &certDataSource,
132 },
133 },
134 expectedErr: nil,
135 expectHTTPListener: false,
136 expectTLSListener: true,
137 }),
138 Entry("with an invalid bind address port", &newServerTableInput{
139 opts: Opts{
140 Handler: handler,
141 BindAddress: "127.0.0.1:a",
142 },
143 expectedErr: errors.New("error setting up listener: listen (tcp, 127.0.0.1:a) failed: listen tcp: "),
144 expectHTTPListener: false,
145 expectTLSListener: false,
146 }),
147 Entry("with an invalid secure bind address port", &newServerTableInput{
148 opts: Opts{
149 Handler: handler,
150 SecureBindAddress: "127.0.0.1:a",
151 TLS: &options.TLS{
152 Key: &keyDataSource,
153 Cert: &certDataSource,
154 },
155 },
156 expectedErr: errors.New("error setting up TLS listener: listen (127.0.0.1:a) failed: listen tcp: "),
157 expectHTTPListener: false,
158 expectTLSListener: false,
159 }),
160 Entry("with an invalid TLS key", &newServerTableInput{
161 opts: Opts{
162 Handler: handler,
163 SecureBindAddress: "127.0.0.1:0",
164 TLS: &options.TLS{
165 Key: &options.SecretSource{
166 Value: []byte("invalid"),
167 },
168 Cert: &certDataSource,
169 },
170 },
171 expectedErr: errors.New("error setting up TLS listener: could not load certificate: could not parse certificate data: tls: failed to find any PEM data in key input"),
172 expectHTTPListener: false,
173 expectTLSListener: false,
174 }),
175 Entry("with an invalid TLS cert", &newServerTableInput{
176 opts: Opts{
177 Handler: handler,
178 SecureBindAddress: "127.0.0.1:0",
179 TLS: &options.TLS{
180 Key: &keyDataSource,
181 Cert: &options.SecretSource{
182 Value: []byte("invalid"),
183 },
184 },
185 },
186 expectedErr: errors.New("error setting up TLS listener: could not load certificate: could not parse certificate data: tls: failed to find any PEM data in certificate input"),
187 expectHTTPListener: false,
188 expectTLSListener: false,
189 }),
190 Entry("with no TLS key", &newServerTableInput{
191 opts: Opts{
192 Handler: handler,
193 SecureBindAddress: "127.0.0.1:0",
194 TLS: &options.TLS{
195 Cert: &certDataSource,
196 },
197 },
198 expectedErr: errors.New("error setting up TLS listener: could not load certificate: could not load key data: no configuration provided"),
199 expectHTTPListener: false,
200 expectTLSListener: false,
201 }),
202 Entry("with no TLS cert", &newServerTableInput{
203 opts: Opts{
204 Handler: handler,
205 SecureBindAddress: "127.0.0.1:0",
206 TLS: &options.TLS{
207 Key: &keyDataSource,
208 },
209 },
210 expectedErr: errors.New("error setting up TLS listener: could not load certificate: could not load cert data: no configuration provided"),
211 expectHTTPListener: false,
212 expectTLSListener: false,
213 }),
214 Entry("when the bind address is prefixed with the http scheme", &newServerTableInput{
215 opts: Opts{
216 Handler: handler,
217 BindAddress: "http://127.0.0.1:0",
218 },
219 expectedErr: nil,
220 expectHTTPListener: true,
221 expectTLSListener: false,
222 }),
223 Entry("when the secure bind address is prefixed with the https scheme", &newServerTableInput{
224 opts: Opts{
225 Handler: handler,
226 SecureBindAddress: "https://127.0.0.1:0",
227 TLS: &options.TLS{
228 Key: &keyDataSource,
229 Cert: &certDataSource,
230 },
231 },
232 expectedErr: nil,
233 expectHTTPListener: false,
234 expectTLSListener: true,
235 }),
236 Entry("with a valid https bind address, and valid TLS config with MinVersion", &newServerTableInput{
237 opts: Opts{
238 Handler: handler,
239 SecureBindAddress: "127.0.0.1:0",
240 TLS: &options.TLS{
241 Key: &keyDataSource,
242 Cert: &certDataSource,
243 MinVersion: "TLS1.3",
244 },
245 },
246 expectedErr: nil,
247 expectHTTPListener: false,
248 expectTLSListener: true,
249 }),
250 Entry("with a valid https bind address, and invalid TLS config with unknown MinVersion", &newServerTableInput{
251 opts: Opts{
252 Handler: handler,
253 SecureBindAddress: "127.0.0.1:0",
254 TLS: &options.TLS{
255 Key: &keyDataSource,
256 Cert: &certDataSource,
257 MinVersion: "TLS1.42",
258 },
259 },
260 expectedErr: errors.New("error setting up TLS listener: unknown TLS MinVersion config provided"),
261 expectHTTPListener: false,
262 expectTLSListener: true,
263 }),
264 )
265 })
267 Context("Start", func() {
268 var srv Server
269 var ctx context.Context
270 var cancel context.CancelFunc
272 BeforeEach(func() {
273 ctx, cancel = context.WithCancel(context.Background())
274 })
276 AfterEach(func() {
277 cancel()
278 })
280 Context("with an http server", func() {
281 var listenAddr string
283 BeforeEach(func() {
284 var err error
285 srv, err = NewServer(Opts{
286 Handler: handler,
287 BindAddress: "127.0.0.1:0",
288 })
289 Expect(err).ToNot(HaveOccurred())
291 s, ok := srv.(*server)
292 Expect(ok).To(BeTrue())
294 listenAddr = fmt.Sprintf("http://%s/", s.listener.Addr().String())
295 })
297 It("Starts the server and serves the handler", func() {
298 go func() {
299 defer GinkgoRecover()
300 Expect(srv.Start(ctx)).To(Succeed())
301 }()
303 resp, err := client.Get(listenAddr)
304 Expect(err).ToNot(HaveOccurred())
305 Expect(resp.StatusCode).To(Equal(http.StatusOK))
307 body, err := ioutil.ReadAll(resp.Body)
308 Expect(err).ToNot(HaveOccurred())
309 Expect(string(body)).To(Equal(hello))
310 })
312 It("Stops the server when the context is cancelled", func() {
313 go func() {
314 defer GinkgoRecover()
315 Expect(srv.Start(ctx)).To(Succeed())
316 }()
318 _, err := client.Get(listenAddr)
319 Expect(err).ToNot(HaveOccurred())
321 cancel()
323 Eventually(func() error {
324 _, err := client.Get(listenAddr)
325 return err
326 }).Should(HaveOccurred())
327 })
328 })
330 Context("with an https server", func() {
331 var secureListenAddr string
333 BeforeEach(func() {
334 var err error
335 srv, err = NewServer(Opts{
336 Handler: handler,
337 SecureBindAddress: "127.0.0.1:0",
338 TLS: &options.TLS{
339 Key: &keyDataSource,
340 Cert: &certDataSource,
341 },
342 })
343 Expect(err).ToNot(HaveOccurred())
345 s, ok := srv.(*server)
346 Expect(ok).To(BeTrue())
348 secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
349 })
351 It("Starts the server and serves the handler", func() {
352 go func() {
353 defer GinkgoRecover()
354 Expect(srv.Start(ctx)).To(Succeed())
355 }()
357 resp, err := client.Get(secureListenAddr)
358 Expect(err).ToNot(HaveOccurred())
359 Expect(resp.StatusCode).To(Equal(http.StatusOK))
361 body, err := ioutil.ReadAll(resp.Body)
362 Expect(err).ToNot(HaveOccurred())
363 Expect(string(body)).To(Equal(hello))
364 })
366 It("Stops the server when the context is cancelled", func() {
367 go func() {
368 defer GinkgoRecover()
369 Expect(srv.Start(ctx)).To(Succeed())
370 }()
372 _, err := client.Get(secureListenAddr)
373 Expect(err).ToNot(HaveOccurred())
375 cancel()
377 Eventually(func() error {
378 _, err := client.Get(secureListenAddr)
379 return err
380 }).Should(HaveOccurred())
381 })
383 It("Serves the certificate provided", func() {
384 go func() {
385 defer GinkgoRecover()
386 Expect(srv.Start(ctx)).To(Succeed())
387 }()
389 resp, err := client.Get(secureListenAddr)
390 Expect(err).ToNot(HaveOccurred())
391 Expect(resp.StatusCode).To(Equal(http.StatusOK))
393 Expect(resp.TLS.VerifiedChains).Should(HaveLen(1))
394 Expect(resp.TLS.VerifiedChains[0]).Should(HaveLen(1))
395 Expect(resp.TLS.VerifiedChains[0][0].Raw).Should(Equal(certData))
396 })
397 })
399 Context("with both an http and an https server", func() {
400 var listenAddr, secureListenAddr string
402 BeforeEach(func() {
403 var err error
404 srv, err = NewServer(Opts{
405 Handler: handler,
406 BindAddress: "127.0.0.1:0",
407 SecureBindAddress: "127.0.0.1:0",
408 TLS: &options.TLS{
409 Key: &keyDataSource,
410 Cert: &certDataSource,
411 },
412 })
413 Expect(err).ToNot(HaveOccurred())
415 s, ok := srv.(*server)
416 Expect(ok).To(BeTrue())
418 listenAddr = fmt.Sprintf("http://%s/", s.listener.Addr().String())
419 secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
420 })
422 It("Starts the server and serves the handler on http", func() {
423 go func() {
424 defer GinkgoRecover()
425 Expect(srv.Start(ctx)).To(Succeed())
426 }()
428 resp, err := client.Get(listenAddr)
429 Expect(err).ToNot(HaveOccurred())
430 Expect(resp.StatusCode).To(Equal(http.StatusOK))
432 body, err := ioutil.ReadAll(resp.Body)
433 Expect(err).ToNot(HaveOccurred())
434 Expect(string(body)).To(Equal(hello))
435 })
437 It("Starts the server and serves the handler on https", func() {
438 go func() {
439 defer GinkgoRecover()
440 Expect(srv.Start(ctx)).To(Succeed())
441 }()
443 resp, err := client.Get(secureListenAddr)
444 Expect(err).ToNot(HaveOccurred())
445 Expect(resp.StatusCode).To(Equal(http.StatusOK))
447 body, err := ioutil.ReadAll(resp.Body)
448 Expect(err).ToNot(HaveOccurred())
449 Expect(string(body)).To(Equal(hello))
450 })
452 It("Stops both servers when the context is cancelled", func() {
453 go func() {
454 defer GinkgoRecover()
455 Expect(srv.Start(ctx)).To(Succeed())
456 }()
458 _, err := client.Get(listenAddr)
459 Expect(err).ToNot(HaveOccurred())
460 _, err = client.Get(secureListenAddr)
461 Expect(err).ToNot(HaveOccurred())
463 cancel()
465 Eventually(func() error {
466 _, err := client.Get(listenAddr)
467 return err
468 }).Should(HaveOccurred())
469 Eventually(func() error {
470 _, err := client.Get(secureListenAddr)
471 return err
472 }).Should(HaveOccurred())
473 })
474 })
475 })
477 Context("getNetworkScheme", func() {
478 DescribeTable("should return the scheme", func(in, expected string) {
479 Expect(getNetworkScheme(in)).To(Equal(expected))
480 },
481 Entry("with no scheme", "127.0.0.1:0", "tcp"),
482 Entry("with a tcp scheme", "tcp://127.0.0.1:0", "tcp"),
483 Entry("with a http scheme", "http://192.168.0.1:1", "tcp"),
484 Entry("with a unix scheme", "unix://172.168.16.2:2", "unix"),
485 Entry("with a random scheme", "random://10.10.10.10:10", "random"),
486 )
487 })
489 Context("getListenAddress", func() {
490 DescribeTable("should remove the scheme", func(in, expected string) {
491 Expect(getListenAddress(in)).To(Equal(expected))
492 },
493 Entry("with no scheme", "127.0.0.1:0", "127.0.0.1:0"),
494 Entry("with a tcp scheme", "tcp://127.0.0.1:0", "127.0.0.1:0"),
495 Entry("with a http scheme", "http://192.168.0.1:1", "192.168.0.1:1"),
496 Entry("with a unix scheme", "unix://172.168.16.2:2", "172.168.16.2:2"),
497 Entry("with a random scheme", "random://10.10.10.10:10", "10.10.10.10:10"),
498 )
499 })
500})