@@ -0,0 +1,472 @@
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"
16+const hello = "Hello World!"
18+var _ = Describe("Server", func() {
19+ handler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
20+ rw.Write([]byte(hello))
23+ Context("NewServer", func() {
24+ type newServerTableInput struct {
27+ expectHTTPListener bool
28+ expectTLSListener bool
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())
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())
48+ Expect(s.tlsListener != nil).To(Equal(in.expectTLSListener))
49+ if in.expectTLSListener {
50+ Expect(s.tlsListener.Close()).To(Succeed())
53+ Entry("with a valid http bind address", &newServerTableInput{
56+ BindAddress: "127.0.0.1:0",
59+ expectHTTPListener: true,
60+ expectTLSListener: false,
62+ Entry("with a valid https bind address, with no TLS config", &newServerTableInput{
65+ SecureBindAddress: "127.0.0.1:0",
67+ expectedErr: errors.New("error setting up TLS listener: no TLS config provided"),
68+ expectHTTPListener: false,
69+ expectTLSListener: false,
71+ Entry("with a valid https bind address, and valid TLS config", &newServerTableInput{
74+ SecureBindAddress: "127.0.0.1:0",
77+ Cert: &certDataSource,
81+ expectHTTPListener: false,
82+ expectTLSListener: true,
84+ Entry("with a both a valid http and valid https bind address, and valid TLS config", &newServerTableInput{
87+ BindAddress: "127.0.0.1:0",
88+ SecureBindAddress: "127.0.0.1:0",
91+ Cert: &certDataSource,
95+ expectHTTPListener: true,
96+ expectTLSListener: true,
98+ Entry("with a \"-\" for the bind address", &newServerTableInput{
104+ expectHTTPListener: false,
105+ expectTLSListener: false,
107+ Entry("with a \"-\" for the secure bind address", &newServerTableInput{
110+ SecureBindAddress: "-",
113+ expectHTTPListener: false,
114+ expectTLSListener: false,
116+ Entry("with an invalid bind address scheme", &newServerTableInput{
119+ BindAddress: "invalid://127.0.0.1:0",
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,
125+ Entry("with an invalid secure bind address scheme", &newServerTableInput{
128+ SecureBindAddress: "invalid://127.0.0.1:0",
130+ Key: &keyDataSource,
131+ Cert: &certDataSource,
135+ expectHTTPListener: false,
136+ expectTLSListener: true,
138+ Entry("with an invalid bind address port", &newServerTableInput{
141+ BindAddress: "127.0.0.1:a",
143+ expectedErr: errors.New("error setting up listener: listen (tcp, 127.0.0.1:a) failed: listen tcp: lookup tcp/a: "),
144+ expectHTTPListener: false,
145+ expectTLSListener: false,
147+ Entry("with an invalid secure bind address port", &newServerTableInput{
150+ SecureBindAddress: "127.0.0.1:a",
152+ Key: &keyDataSource,
153+ Cert: &certDataSource,
156+ expectedErr: errors.New("error setting up TLS listener: listen (127.0.0.1:a) failed: listen tcp: lookup tcp/a: "),
157+ expectHTTPListener: false,
158+ expectTLSListener: false,
160+ Entry("with an invalid TLS key", &newServerTableInput{
163+ SecureBindAddress: "127.0.0.1:0",
165+ Key: &options.SecretSource{
166+ Value: []byte("invalid"),
168+ Cert: &certDataSource,
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,
175+ Entry("with an invalid TLS cert", &newServerTableInput{
178+ SecureBindAddress: "127.0.0.1:0",
180+ Key: &keyDataSource,
181+ Cert: &options.SecretSource{
182+ Value: []byte("invalid"),
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,
190+ Entry("with no TLS key", &newServerTableInput{
193+ SecureBindAddress: "127.0.0.1:0",
195+ Cert: &certDataSource,
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,
202+ Entry("with no TLS cert", &newServerTableInput{
205+ SecureBindAddress: "127.0.0.1:0",
207+ Key: &keyDataSource,
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,
214+ Entry("when the bind address is prefixed with the http scheme", &newServerTableInput{
217+ BindAddress: "http://127.0.0.1:0",
220+ expectHTTPListener: true,
221+ expectTLSListener: false,
223+ Entry("when the secure bind address is prefixed with the https scheme", &newServerTableInput{
226+ SecureBindAddress: "https://127.0.0.1:0",
228+ Key: &keyDataSource,
229+ Cert: &certDataSource,
233+ expectHTTPListener: false,
234+ expectTLSListener: true,
239+ Context("Start", func() {
241+ var ctx context.Context
242+ var cancel context.CancelFunc
245+ ctx, cancel = context.WithCancel(context.Background())
252+ Context("with an http server", func() {
253+ var listenAddr string
257+ srv, err = NewServer(Opts{
259+ BindAddress: "127.0.0.1:0",
261+ Expect(err).ToNot(HaveOccurred())
263+ s, ok := srv.(*server)
264+ Expect(ok).To(BeTrue())
266+ listenAddr = fmt.Sprintf("http://%s/", s.listener.Addr().String())
269+ It("Starts the server and serves the handler", func() {
271+ defer GinkgoRecover()
272+ Expect(srv.Start(ctx)).To(Succeed())
275+ resp, err := client.Get(listenAddr)
276+ Expect(err).ToNot(HaveOccurred())
277+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
279+ body, err := ioutil.ReadAll(resp.Body)
280+ Expect(err).ToNot(HaveOccurred())
281+ Expect(string(body)).To(Equal(hello))
284+ It("Stops the server when the context is cancelled", func() {
286+ defer GinkgoRecover()
287+ Expect(srv.Start(ctx)).To(Succeed())
290+ _, err := client.Get(listenAddr)
291+ Expect(err).ToNot(HaveOccurred())
295+ Eventually(func() error {
296+ _, err := client.Get(listenAddr)
298+ }).Should(HaveOccurred())
302+ Context("with an https server", func() {
303+ var secureListenAddr string
307+ srv, err = NewServer(Opts{
309+ SecureBindAddress: "127.0.0.1:0",
311+ Key: &keyDataSource,
312+ Cert: &certDataSource,
315+ Expect(err).ToNot(HaveOccurred())
317+ s, ok := srv.(*server)
318+ Expect(ok).To(BeTrue())
320+ secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
323+ It("Starts the server and serves the handler", func() {
325+ defer GinkgoRecover()
326+ Expect(srv.Start(ctx)).To(Succeed())
329+ resp, err := client.Get(secureListenAddr)
330+ Expect(err).ToNot(HaveOccurred())
331+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
333+ body, err := ioutil.ReadAll(resp.Body)
334+ Expect(err).ToNot(HaveOccurred())
335+ Expect(string(body)).To(Equal(hello))
338+ It("Stops the server when the context is cancelled", func() {
340+ defer GinkgoRecover()
341+ Expect(srv.Start(ctx)).To(Succeed())
344+ _, err := client.Get(secureListenAddr)
345+ Expect(err).ToNot(HaveOccurred())
349+ Eventually(func() error {
350+ _, err := client.Get(secureListenAddr)
352+ }).Should(HaveOccurred())
355+ It("Serves the certificate provided", func() {
357+ defer GinkgoRecover()
358+ Expect(srv.Start(ctx)).To(Succeed())
361+ resp, err := client.Get(secureListenAddr)
362+ Expect(err).ToNot(HaveOccurred())
363+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
365+ Expect(resp.TLS.VerifiedChains).Should(HaveLen(1))
366+ Expect(resp.TLS.VerifiedChains[0]).Should(HaveLen(1))
367+ Expect(resp.TLS.VerifiedChains[0][0].Raw).Should(Equal(certData))
371+ Context("with both an http and an https server", func() {
372+ var listenAddr, secureListenAddr string
376+ srv, err = NewServer(Opts{
378+ BindAddress: "127.0.0.1:0",
379+ SecureBindAddress: "127.0.0.1:0",
381+ Key: &keyDataSource,
382+ Cert: &certDataSource,
385+ Expect(err).ToNot(HaveOccurred())
387+ s, ok := srv.(*server)
388+ Expect(ok).To(BeTrue())
390+ listenAddr = fmt.Sprintf("http://%s/", s.listener.Addr().String())
391+ secureListenAddr = fmt.Sprintf("https://%s/", s.tlsListener.Addr().String())
394+ It("Starts the server and serves the handler on http", func() {
396+ defer GinkgoRecover()
397+ Expect(srv.Start(ctx)).To(Succeed())
400+ resp, err := client.Get(listenAddr)
401+ Expect(err).ToNot(HaveOccurred())
402+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
404+ body, err := ioutil.ReadAll(resp.Body)
405+ Expect(err).ToNot(HaveOccurred())
406+ Expect(string(body)).To(Equal(hello))
409+ It("Starts the server and serves the handler on https", func() {
411+ defer GinkgoRecover()
412+ Expect(srv.Start(ctx)).To(Succeed())
415+ resp, err := client.Get(secureListenAddr)
416+ Expect(err).ToNot(HaveOccurred())
417+ Expect(resp.StatusCode).To(Equal(http.StatusOK))
419+ body, err := ioutil.ReadAll(resp.Body)
420+ Expect(err).ToNot(HaveOccurred())
421+ Expect(string(body)).To(Equal(hello))
424+ It("Stops both servers when the context is cancelled", func() {
426+ defer GinkgoRecover()
427+ Expect(srv.Start(ctx)).To(Succeed())
430+ _, err := client.Get(listenAddr)
431+ Expect(err).ToNot(HaveOccurred())
432+ _, err = client.Get(secureListenAddr)
433+ Expect(err).ToNot(HaveOccurred())
437+ Eventually(func() error {
438+ _, err := client.Get(listenAddr)
440+ }).Should(HaveOccurred())
441+ Eventually(func() error {
442+ _, err := client.Get(secureListenAddr)
444+ }).Should(HaveOccurred())
449+ Context("getNetworkScheme", func() {
450+ DescribeTable("should return the scheme", func(in, expected string) {
451+ Expect(getNetworkScheme(in)).To(Equal(expected))
453+ Entry("with no scheme", "127.0.0.1:0", "tcp"),
454+ Entry("with a tcp scheme", "tcp://127.0.0.1:0", "tcp"),
455+ Entry("with a http scheme", "http://192.168.0.1:1", "tcp"),
456+ Entry("with a unix scheme", "unix://172.168.16.2:2", "unix"),
457+ Entry("with a random scheme", "random://10.10.10.10:10", "random"),
461+ Context("getListenAddress", func() {
462+ DescribeTable("should remove the scheme", func(in, expected string) {
463+ Expect(getListenAddress(in)).To(Equal(expected))
465+ Entry("with no scheme", "127.0.0.1:0", "127.0.0.1:0"),
466+ Entry("with a tcp scheme", "tcp://127.0.0.1:0", "127.0.0.1:0"),
467+ Entry("with a http scheme", "http://192.168.0.1:1", "192.168.0.1:1"),
468+ Entry("with a unix scheme", "unix://172.168.16.2:2", "172.168.16.2:2"),
469+ Entry("with a random scheme", "random://10.10.10.10:10", "10.10.10.10:10"),