github.com/openshift-online/ocm-sdk-go@v0.1.473/authentication/handler_test.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  /*
     5  Copyright (c) 2019 Red Hat, Inc.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11    http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  // This file contains tests for the authentication handler.
    21  
    22  package authentication
    23  
    24  import (
    25  	"net/http"
    26  	"net/http/httptest"
    27  	"os"
    28  	"time"
    29  
    30  	"github.com/golang-jwt/jwt/v4"
    31  
    32  	. "github.com/onsi/ginkgo/v2/dsl/core"
    33  	. "github.com/onsi/gomega"                         // nolint
    34  	. "github.com/onsi/gomega/ghttp"                   // nolint
    35  	. "github.com/openshift-online/ocm-sdk-go/testing" // nolint
    36  )
    37  
    38  var _ = Describe("Handler", func() {
    39  	It("Can't be built without a logger", func() {
    40  		// Prepare the next handler:
    41  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    42  			w.WriteHeader(http.StatusOK)
    43  		})
    44  
    45  		// Try to create the handler:
    46  		_, err := NewHandler().
    47  			KeysFile(keysFile).
    48  			Next(next).
    49  			Build()
    50  		Expect(err).To(HaveOccurred())
    51  		Expect(err.Error()).To(ContainSubstring("logger"))
    52  		Expect(err.Error()).To(ContainSubstring("mandatory"))
    53  	})
    54  
    55  	It("Can't be built without at least one keys source", func() {
    56  		// Prepare the next handler:
    57  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    58  			w.WriteHeader(http.StatusOK)
    59  		})
    60  
    61  		// Try to create the handler:
    62  		_, err := NewHandler().
    63  			Logger(logger).
    64  			Next(next).
    65  			Build()
    66  		Expect(err).To(HaveOccurred())
    67  	})
    68  
    69  	It("Can't be built with a keys file that doesn't exist", func() {
    70  		// Prepare the next handler:
    71  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    72  			w.WriteHeader(http.StatusOK)
    73  		})
    74  
    75  		// Try to create the handler:
    76  		_, err := NewHandler().
    77  			Logger(logger).
    78  			KeysFile("/does/not/exist").
    79  			Next(next).
    80  			Build()
    81  		Expect(err).To(HaveOccurred())
    82  		Expect(err.Error()).To(ContainSubstring("/does/not/exist"))
    83  	})
    84  
    85  	It("Can't be built with a malformed keys URL", func() {
    86  		// Prepare the next handler:
    87  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    88  			w.WriteHeader(http.StatusOK)
    89  		})
    90  
    91  		// Try to create the handler:
    92  		_, err := NewHandler().
    93  			Logger(logger).
    94  			KeysURL("junk").
    95  			Next(next).
    96  			Build()
    97  		Expect(err).To(HaveOccurred())
    98  		Expect(err.Error()).To(ContainSubstring("junk"))
    99  	})
   100  
   101  	It("Can't be built with a URL that isn't HTTPS", func() {
   102  		// Prepare the next handler:
   103  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   104  			w.WriteHeader(http.StatusOK)
   105  		})
   106  
   107  		// Try to create the handler:
   108  		_, err := NewHandler().
   109  			Logger(logger).
   110  			KeysURL("http://api.openshift.com/.well-known/jwks.json").
   111  			Next(next).
   112  			Build()
   113  		Expect(err).To(HaveOccurred())
   114  	})
   115  
   116  	It("Can be built with one keys file", func() {
   117  		// Prepare the next handler:
   118  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   119  			w.WriteHeader(http.StatusOK)
   120  		})
   121  
   122  		// Try to create the handler:
   123  		_, err := NewHandler().
   124  			Logger(logger).
   125  			KeysFile(keysFile).
   126  			Next(next).
   127  			Build()
   128  		Expect(err).ToNot(HaveOccurred())
   129  	})
   130  
   131  	It("Can be built with one keys URL", func() {
   132  		// Prepare the next handler:
   133  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   134  			w.WriteHeader(http.StatusOK)
   135  		})
   136  
   137  		// Try to create the handler:
   138  		_, err := NewHandler().
   139  			Logger(logger).
   140  			KeysURL("https://api.openshift.com/.well-known/jwks.json").
   141  			Next(next).
   142  			Build()
   143  		Expect(err).ToNot(HaveOccurred())
   144  	})
   145  
   146  	It("Can't be built without a next handler", func() {
   147  		_, err := NewHandler().
   148  			Logger(logger).
   149  			KeysFile(keysFile).
   150  			Build()
   151  		Expect(err).To(HaveOccurred())
   152  		Expect(err.Error()).To(ContainSubstring("next"))
   153  		Expect(err.Error()).To(ContainSubstring("mandatory"))
   154  	})
   155  
   156  	It("Rejects request without authorization header or cookie", func() {
   157  		// Prepare the next handler, which should not be called:
   158  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   159  			Expect(true).To(BeFalse())
   160  			w.WriteHeader(http.StatusBadRequest)
   161  		})
   162  
   163  		// Prepare the handler:
   164  		handler, err := NewHandler().
   165  			Logger(logger).
   166  			KeysFile(keysFile).
   167  			Next(next).
   168  			Build()
   169  		Expect(err).ToNot(HaveOccurred())
   170  
   171  		// Send the request:
   172  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   173  		recorder := httptest.NewRecorder()
   174  		handler.ServeHTTP(recorder, request)
   175  
   176  		// Verify that the request is rejected:
   177  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   178  		Expect(recorder.Body).To(MatchJSON(`{
   179  			"kind": "Error",
   180  			"id": "401",
   181  			"href": "/api/clusters_mgmt/v1/errors/401",
   182  			"code": "CLUSTERS-MGMT-401",
   183  			"reason": "Request doesn't contain the 'Authorization' header or the 'cs_jwt' cookie"
   184  		}`))
   185  	})
   186  
   187  	It("Rejects bad authorization type", func() {
   188  		// Prepare the next handler, which should not be called:
   189  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   190  			Expect(true).To(BeFalse())
   191  			w.WriteHeader(http.StatusBadRequest)
   192  		})
   193  
   194  		// Prepare the token:
   195  		bearer := MakeTokenString("Bearer", 1*time.Minute)
   196  
   197  		// Prepare the handler:
   198  		handler, err := NewHandler().
   199  			Logger(logger).
   200  			KeysFile(keysFile).
   201  			Next(next).
   202  			Build()
   203  		Expect(err).ToNot(HaveOccurred())
   204  
   205  		// Send the request with a bad type and a good token:
   206  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   207  		request.Header.Set("Authorization", "Bad "+bearer)
   208  		recorder := httptest.NewRecorder()
   209  		handler.ServeHTTP(recorder, request)
   210  
   211  		// Verify that the request is rejected:
   212  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   213  		Expect(recorder.Body).To(MatchJSON(`{
   214  			"kind": "Error",
   215  			"id": "401",
   216  			"href": "/api/clusters_mgmt/v1/errors/401",
   217  			"code": "CLUSTERS-MGMT-401",
   218  			"reason": "Authentication type 'Bad' isn't supported"
   219  		}`))
   220  	})
   221  
   222  	It("Rejects bad bearer token", func() {
   223  		// Prepare the next handler, which should not be called:
   224  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   225  			Expect(true).To(BeFalse())
   226  			w.WriteHeader(http.StatusBadRequest)
   227  		})
   228  
   229  		// Prepare the handler:
   230  		handler, err := NewHandler().
   231  			Logger(logger).
   232  			KeysFile(keysFile).
   233  			Next(next).
   234  			Build()
   235  		Expect(err).ToNot(HaveOccurred())
   236  
   237  		// Send the request with a bad type and a good token:
   238  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   239  		request.Header.Set("Authorization", "Bearer bad")
   240  		recorder := httptest.NewRecorder()
   241  		handler.ServeHTTP(recorder, request)
   242  
   243  		// Verify that the request is rejected:
   244  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   245  		Expect(recorder.Body).To(MatchJSON(`{
   246  			"kind": "Error",
   247  			"id": "401",
   248  			"href": "/api/clusters_mgmt/v1/errors/401",
   249  			"code": "CLUSTERS-MGMT-401",
   250  			"reason": "Bearer token is malformed"
   251  		}`))
   252  	})
   253  
   254  	It("Rejects expired bearer token", func() {
   255  		// Prepare the next handler, which should not be called:
   256  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   257  			Expect(true).To(BeFalse())
   258  			w.WriteHeader(http.StatusBadRequest)
   259  		})
   260  
   261  		// Prepare the expired token:
   262  		bearer := MakeTokenString("Bearer", -1*time.Hour)
   263  
   264  		// Prepare the handler:
   265  		handler, err := NewHandler().
   266  			Logger(logger).
   267  			KeysFile(keysFile).
   268  			Next(next).
   269  			Build()
   270  		Expect(err).ToNot(HaveOccurred())
   271  
   272  		// Send the request with the expired token:
   273  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   274  		request.Header.Set("Authorization", "Bearer "+bearer)
   275  		recorder := httptest.NewRecorder()
   276  		handler.ServeHTTP(recorder, request)
   277  
   278  		// Verify that the request is rejected:
   279  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   280  		Expect(recorder.Body).To(MatchJSON(`{
   281  			"kind": "Error",
   282  			"id": "401",
   283  			"href": "/api/clusters_mgmt/v1/errors/401",
   284  			"code": "CLUSTERS-MGMT-401",
   285  			"reason": "Bearer token is expired"
   286  		}`))
   287  	})
   288  
   289  	It("Accepts token without `typ` claim", func() {
   290  		// Prepare the next handler:
   291  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   292  			w.WriteHeader(http.StatusOK)
   293  		})
   294  
   295  		// Prepare a token without the 'typ' claim:
   296  		bearer := MakeTokenObject(jwt.MapClaims{
   297  			"typ": nil,
   298  		}).Raw
   299  
   300  		// Prepare the handler:
   301  		handler, err := NewHandler().
   302  			Logger(logger).
   303  			KeysFile(keysFile).
   304  			Next(next).
   305  			Build()
   306  		Expect(err).ToNot(HaveOccurred())
   307  
   308  		// Send the request with the bad token:
   309  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   310  		request.Header.Set("Authorization", "Bearer "+bearer)
   311  		recorder := httptest.NewRecorder()
   312  		handler.ServeHTTP(recorder, request)
   313  
   314  		// Verify that the request is accepted:
   315  		Expect(recorder.Code).To(Equal(http.StatusOK))
   316  	})
   317  
   318  	It("Rejects `typ` claim with incorrect type", func() {
   319  		// Prepare the next handler, which should not be called:
   320  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   321  			Expect(true).To(BeFalse())
   322  			w.WriteHeader(http.StatusBadRequest)
   323  		})
   324  
   325  		// Prepare a refresh token:
   326  		bearer := MakeTokenObject(jwt.MapClaims{
   327  			"typ": 123,
   328  		}).Raw
   329  
   330  		// Prepare the handler:
   331  		handler, err := NewHandler().
   332  			Logger(logger).
   333  			KeysFile(keysFile).
   334  			Next(next).
   335  			Build()
   336  		Expect(err).ToNot(HaveOccurred())
   337  
   338  		// Send the request with the bad token:
   339  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   340  		request.Header.Set("Authorization", "Bearer "+bearer)
   341  		recorder := httptest.NewRecorder()
   342  		handler.ServeHTTP(recorder, request)
   343  
   344  		// Verify that the request is rejected:
   345  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   346  		Expect(recorder.Body).To(MatchJSON(`{
   347  			"kind": "Error",
   348  			"id": "401",
   349  			"href": "/api/clusters_mgmt/v1/errors/401",
   350  			"code": "CLUSTERS-MGMT-401",
   351  			"reason": "Bearer token type claim contains incorrect string value '123'"
   352  		}`))
   353  	})
   354  
   355  	It("Rejects refresh tokens", func() {
   356  		// Prepare the next handler, which should not be called:
   357  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   358  			Expect(true).To(BeFalse())
   359  			w.WriteHeader(http.StatusBadRequest)
   360  		})
   361  
   362  		// Prepare a refresh token:
   363  		bearer := MakeTokenString("Refresh", 1*time.Hour)
   364  
   365  		// Prepare the handler:
   366  		handler, err := NewHandler().
   367  			Logger(logger).
   368  			KeysFile(keysFile).
   369  			Next(next).
   370  			Build()
   371  		Expect(err).ToNot(HaveOccurred())
   372  
   373  		// Send the request with the bad token:
   374  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   375  		request.Header.Set("Authorization", "Bearer "+bearer)
   376  		recorder := httptest.NewRecorder()
   377  		handler.ServeHTTP(recorder, request)
   378  
   379  		// Verify that the request is rejected:
   380  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   381  		Expect(recorder.Body).To(MatchJSON(`{
   382  			"kind": "Error",
   383  			"id": "401",
   384  			"href": "/api/clusters_mgmt/v1/errors/401",
   385  			"code": "CLUSTERS-MGMT-401",
   386  			"reason": "Bearer token type 'Refresh' isn't allowed"
   387  		}`))
   388  	})
   389  
   390  	It("Rejects offline tokens", func() {
   391  		// Prepare the next handler, which should not be called:
   392  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   393  			Expect(true).To(BeFalse())
   394  			w.WriteHeader(http.StatusBadRequest)
   395  		})
   396  
   397  		// Prepare an offline access token:
   398  		bearer := MakeTokenString("Offline", 0)
   399  
   400  		// Prepare the handler:
   401  		handler, err := NewHandler().
   402  			Logger(logger).
   403  			KeysFile(keysFile).
   404  			Next(next).
   405  			Build()
   406  		Expect(err).ToNot(HaveOccurred())
   407  
   408  		// Send the request with the bad token:
   409  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   410  		request.Header.Set("Authorization", "Bearer "+bearer)
   411  		recorder := httptest.NewRecorder()
   412  		handler.ServeHTTP(recorder, request)
   413  
   414  		// Verify that the request is rejected:
   415  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   416  		Expect(recorder.Body).To(MatchJSON(`{
   417  			"kind": "Error",
   418  			"id": "401",
   419  			"href": "/api/clusters_mgmt/v1/errors/401",
   420  			"code": "CLUSTERS-MGMT-401",
   421  			"reason": "Bearer token type 'Offline' isn't allowed"
   422  		}`))
   423  	})
   424  
   425  	It("Rejects token without issue date", func() {
   426  		// Prepare the next handler, which should not be called:
   427  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   428  			Expect(true).To(BeFalse())
   429  			w.WriteHeader(http.StatusBadRequest)
   430  		})
   431  
   432  		// Prepare the token without the 'iat' claim:
   433  		token := MakeTokenObject(jwt.MapClaims{
   434  			"typ": "Bearer",
   435  			"iat": nil,
   436  		})
   437  		bearer := token.Raw
   438  
   439  		// Prepare the handler:
   440  		handler, err := NewHandler().
   441  			Logger(logger).
   442  			KeysFile(keysFile).
   443  			Next(next).
   444  			Build()
   445  		Expect(err).ToNot(HaveOccurred())
   446  
   447  		// Send the request with the bad token:
   448  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   449  		request.Header.Set("Authorization", "Bearer "+bearer)
   450  		recorder := httptest.NewRecorder()
   451  		handler.ServeHTTP(recorder, request)
   452  
   453  		// Verify that the request is rejected:
   454  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   455  		Expect(recorder.Body).To(MatchJSON(`{
   456  			"kind": "Error",
   457  			"id": "401",
   458  			"href": "/api/clusters_mgmt/v1/errors/401",
   459  			"code": "CLUSTERS-MGMT-401",
   460  			"reason": "Bearer token doesn't contain required claim 'iat'"
   461  		}`))
   462  	})
   463  
   464  	It("Rejects token without expiration date", func() {
   465  		// Prepare the next handler, which should not be called:
   466  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   467  			Expect(true).To(BeFalse())
   468  			w.WriteHeader(http.StatusBadRequest)
   469  		})
   470  
   471  		// Prepare the token without the 'exp' claim:
   472  		token := MakeTokenObject(jwt.MapClaims{
   473  			"typ": "Bearer",
   474  			"exp": nil,
   475  		})
   476  		bearer := token.Raw
   477  
   478  		// Prepare the handler:
   479  		handler, err := NewHandler().
   480  			Logger(logger).
   481  			KeysFile(keysFile).
   482  			Next(next).
   483  			Build()
   484  		Expect(err).ToNot(HaveOccurred())
   485  
   486  		// Send the request with the bad token:
   487  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   488  		request.Header.Set("Authorization", "Bearer "+bearer)
   489  		recorder := httptest.NewRecorder()
   490  		handler.ServeHTTP(recorder, request)
   491  
   492  		// Verify that the request is rejected:
   493  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   494  		Expect(recorder.Body).To(MatchJSON(`{
   495  			"kind": "Error",
   496  			"id": "401",
   497  			"href": "/api/clusters_mgmt/v1/errors/401",
   498  			"code": "CLUSTERS-MGMT-401",
   499  			"reason": "Bearer token doesn't contain required claim 'exp'"
   500  		}`))
   501  	})
   502  
   503  	It("Rejects token issued in the future", func() {
   504  		// Prepare the next handler, which should not be called:
   505  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   506  			Expect(true).To(BeFalse())
   507  			w.WriteHeader(http.StatusBadRequest)
   508  		})
   509  
   510  		// Prepare a token issued in the future:
   511  		now := time.Now()
   512  		iat := now.Add(1 * time.Minute)
   513  		exp := iat.Add(1 * time.Minute)
   514  		token := MakeTokenObject(jwt.MapClaims{
   515  			"typ": "Bearer",
   516  			"iat": iat.Unix(),
   517  			"exp": exp.Unix(),
   518  		})
   519  		bearer := token.Raw
   520  
   521  		// Prepare the handler:
   522  		handler, err := NewHandler().
   523  			Logger(logger).
   524  			KeysFile(keysFile).
   525  			Next(next).
   526  			Build()
   527  		Expect(err).ToNot(HaveOccurred())
   528  
   529  		// Send the request with the bad token:
   530  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   531  		request.Header.Set("Authorization", "Bearer "+bearer)
   532  		recorder := httptest.NewRecorder()
   533  		handler.ServeHTTP(recorder, request)
   534  
   535  		// Verify that the request is rejected:
   536  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   537  		Expect(recorder.Body).To(MatchJSON(`{
   538  			"kind": "Error",
   539  			"id": "401",
   540  			"href": "/api/clusters_mgmt/v1/errors/401",
   541  			"code": "CLUSTERS-MGMT-401",
   542  			"reason": "Bearer token was issued in the future"
   543  		}`))
   544  	})
   545  
   546  	It("Rejects token that isn't valid yet", func() {
   547  		// Prepare the next handler, which should not be called:
   548  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   549  			Expect(true).To(BeFalse())
   550  			w.WriteHeader(http.StatusBadRequest)
   551  		})
   552  
   553  		// Prepare the not yet valid token:
   554  		iat := time.Now()
   555  		nbf := iat.Add(1 * time.Minute)
   556  		exp := nbf.Add(1 * time.Minute)
   557  		token := MakeTokenObject(jwt.MapClaims{
   558  			"typ": "Bearer",
   559  			"iat": iat.Unix(),
   560  			"nbf": nbf.Unix(),
   561  			"exp": exp.Unix(),
   562  		})
   563  		bearer := token.Raw
   564  
   565  		// Prepare the handler:
   566  		handler, err := NewHandler().
   567  			Logger(logger).
   568  			KeysFile(keysFile).
   569  			Next(next).
   570  			Build()
   571  		Expect(err).ToNot(HaveOccurred())
   572  
   573  		// Send the request with a bad token:
   574  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   575  		request.Header.Set("Authorization", "Bearer "+bearer)
   576  		recorder := httptest.NewRecorder()
   577  		handler.ServeHTTP(recorder, request)
   578  
   579  		// Verify that the request is rejected:
   580  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   581  		Expect(recorder.Body).To(MatchJSON(`{
   582  			"kind": "Error",
   583  			"id": "401",
   584  			"href": "/api/clusters_mgmt/v1/errors/401",
   585  			"code": "CLUSTERS-MGMT-401",
   586  			"reason": "Bearer token isn't valid yet"
   587  		}`))
   588  	})
   589  
   590  	It("Rejects impersonated token", func() {
   591  		// Prepare the next handler, which should not be called:
   592  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   593  			Expect(true).To(BeFalse())
   594  			w.WriteHeader(http.StatusBadRequest)
   595  		})
   596  
   597  		// Prepare the impersonated token:
   598  		token := MakeTokenObject(jwt.MapClaims{
   599  			"impersonated": true,
   600  		})
   601  		bearer := token.Raw
   602  
   603  		// Prepare the handler:
   604  		handler, err := NewHandler().
   605  			Logger(logger).
   606  			KeysFile(keysFile).
   607  			Next(next).
   608  			Build()
   609  		Expect(err).ToNot(HaveOccurred())
   610  
   611  		// Send the request:
   612  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   613  		request.Header.Set("Authorization", "Bearer "+bearer)
   614  		recorder := httptest.NewRecorder()
   615  		handler.ServeHTTP(recorder, request)
   616  
   617  		// Verify that the request is rejected:
   618  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   619  		Expect(recorder.Body).To(MatchJSON(`{
   620  			"kind": "Error",
   621  			"id": "401",
   622  			"href": "/api/clusters_mgmt/v1/errors/401",
   623  			"code": "CLUSTERS-MGMT-401",
   624  			"reason": "Impersonation isn't allowed"
   625  		}`))
   626  	})
   627  
   628  	It("Rejects bad impersonated claim", func() {
   629  		// Prepare the next handler, which should not be called:
   630  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   631  			Expect(true).To(BeFalse())
   632  			w.WriteHeader(http.StatusBadRequest)
   633  		})
   634  
   635  		// Prepare the impersonated token:
   636  		token := MakeTokenObject(jwt.MapClaims{
   637  			"impersonated": "junk",
   638  		})
   639  		bearer := token.Raw
   640  
   641  		// Prepare the handler:
   642  		handler, err := NewHandler().
   643  			Logger(logger).
   644  			KeysFile(keysFile).
   645  			Next(next).
   646  			Build()
   647  		Expect(err).ToNot(HaveOccurred())
   648  
   649  		// Send the request:
   650  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   651  		request.Header.Set("Authorization", "Bearer "+bearer)
   652  		recorder := httptest.NewRecorder()
   653  		handler.ServeHTTP(recorder, request)
   654  
   655  		// Verify that the request is rejected:
   656  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   657  		Expect(recorder.Body).To(MatchJSON(`{
   658  			"kind": "Error",
   659  			"id": "401",
   660  			"href": "/api/clusters_mgmt/v1/errors/401",
   661  			"code": "CLUSTERS-MGMT-401",
   662  			"reason": "Impersonation claim contains incorrect boolean value 'junk'"
   663  		}`))
   664  	})
   665  
   666  	It("Accepts false impersonated claim", func() {
   667  		// Prepare the next handler:
   668  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   669  			w.WriteHeader(http.StatusOK)
   670  		})
   671  
   672  		// Prepare the impersonated token:
   673  		token := MakeTokenObject(jwt.MapClaims{
   674  			"impersonated": false,
   675  		})
   676  		bearer := token.Raw
   677  
   678  		// Prepare the handler:
   679  		handler, err := NewHandler().
   680  			Logger(logger).
   681  			KeysFile(keysFile).
   682  			Next(next).
   683  			Build()
   684  		Expect(err).ToNot(HaveOccurred())
   685  
   686  		// Send the request:
   687  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   688  		request.Header.Set("Authorization", "Bearer "+bearer)
   689  		recorder := httptest.NewRecorder()
   690  		handler.ServeHTTP(recorder, request)
   691  
   692  		// Verify the response:
   693  		Expect(recorder.Code).To(Equal(http.StatusOK))
   694  	})
   695  
   696  	It("Loads keys from file", func() {
   697  		// Prepare the next handler:
   698  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   699  			w.WriteHeader(http.StatusOK)
   700  		})
   701  
   702  		// Prepare the token:
   703  		bearer := MakeTokenString("Bearer", 1*time.Minute)
   704  
   705  		// Prepare the handler:
   706  		handler, err := NewHandler().
   707  			Logger(logger).
   708  			KeysFile(keysFile).
   709  			Next(next).
   710  			Build()
   711  		Expect(err).ToNot(HaveOccurred())
   712  
   713  		// Send the request:
   714  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   715  		request.Header.Set("Authorization", "Bearer "+bearer)
   716  		recorder := httptest.NewRecorder()
   717  		handler.ServeHTTP(recorder, request)
   718  
   719  		// Verify that the request is rejected:
   720  		Expect(recorder.Code).To(Equal(http.StatusOK))
   721  	})
   722  
   723  	It("Adds token to the request context", func() {
   724  		// Prepare the token:
   725  		bearer := MakeTokenString("Bearer", 1*time.Minute)
   726  
   727  		// Prepare the next handler:
   728  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   729  			actual, err := BearerFromContext(r.Context())
   730  			Expect(err).ToNot(HaveOccurred())
   731  			Expect(actual).To(Equal(bearer))
   732  			w.WriteHeader(http.StatusOK)
   733  		})
   734  
   735  		// Prepare the handler:
   736  		handler, err := NewHandler().
   737  			Logger(logger).
   738  			KeysFile(keysFile).
   739  			Next(next).
   740  			Build()
   741  		Expect(err).ToNot(HaveOccurred())
   742  
   743  		// Send the request:
   744  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   745  		request.Header.Set("Authorization", "Bearer "+bearer)
   746  		recorder := httptest.NewRecorder()
   747  		handler.ServeHTTP(recorder, request)
   748  
   749  		// Verify the response:
   750  		Expect(recorder.Code).To(Equal(http.StatusOK))
   751  	})
   752  
   753  	It("Doesn't require authorization header for public URL", func() {
   754  		// Prepare the next handler:
   755  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   756  			actual, err := BearerFromContext(r.Context())
   757  			Expect(err).ToNot(HaveOccurred())
   758  			Expect(actual).To(BeEmpty())
   759  			w.WriteHeader(http.StatusOK)
   760  		})
   761  
   762  		// Prepare the handler:
   763  		handler, err := NewHandler().
   764  			Logger(logger).
   765  			KeysFile(keysFile).
   766  			Public("^/api/clusters_mgmt/v1/public(/.*)?$").
   767  			Next(next).
   768  			Build()
   769  		Expect(err).ToNot(HaveOccurred())
   770  
   771  		// Send the request without the authorization header:
   772  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/public", nil)
   773  		recorder := httptest.NewRecorder()
   774  		handler.ServeHTTP(recorder, request)
   775  
   776  		// Verify the response:
   777  		Expect(recorder.Code).To(Equal(http.StatusOK))
   778  	})
   779  
   780  	It("Ignores malformed authorization header for public URL", func() {
   781  		// Prepare the next handler:
   782  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   783  			actual, err := BearerFromContext(r.Context())
   784  			Expect(err).ToNot(HaveOccurred())
   785  			Expect(actual).To(BeEmpty())
   786  			w.WriteHeader(http.StatusOK)
   787  		})
   788  
   789  		// Prepare the handler:
   790  		handler, err := NewHandler().
   791  			Logger(logger).
   792  			KeysFile(keysFile).
   793  			Public("^/api/clusters_mgmt/v1/public(/.*)?$").
   794  			Next(next).
   795  			Build()
   796  		Expect(err).ToNot(HaveOccurred())
   797  
   798  		// Send the request:
   799  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/public", nil)
   800  		request.Header.Set("Authorization", "Bad junk")
   801  		recorder := httptest.NewRecorder()
   802  		handler.ServeHTTP(recorder, request)
   803  	})
   804  
   805  	It("Ignores expired token for public URL", func() {
   806  		// Prepare the expired token:
   807  		bearer := MakeTokenString("Bearer", -1*time.Minute)
   808  
   809  		// Prepare the next handler:
   810  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   811  			bearer, err := BearerFromContext(r.Context())
   812  			Expect(err).ToNot(HaveOccurred())
   813  			Expect(bearer).To(BeEmpty())
   814  			w.WriteHeader(http.StatusOK)
   815  		})
   816  
   817  		// Prepare the handler:
   818  		handler, err := NewHandler().
   819  			Logger(logger).
   820  			KeysFile(keysFile).
   821  			Public("^/api/clusters_mgmt/v1/public(/.*)?$").
   822  			Next(next).
   823  			Build()
   824  		Expect(err).ToNot(HaveOccurred())
   825  
   826  		// Send the request:
   827  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/public", nil)
   828  		request.Header.Set("Authorization", "Bearer "+bearer)
   829  		recorder := httptest.NewRecorder()
   830  		handler.ServeHTTP(recorder, request)
   831  	})
   832  
   833  	It("Combines multiple public URLs", func() {
   834  		// Prepare the token:
   835  		bearer := MakeTokenString("Bearer", 1*time.Minute)
   836  
   837  		// Prepare the next handler:
   838  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   839  			actual, err := BearerFromContext(r.Context())
   840  			Expect(err).ToNot(HaveOccurred())
   841  			Expect(actual).To(BeEmpty())
   842  			w.WriteHeader(http.StatusOK)
   843  		})
   844  
   845  		// Prepare the handler:
   846  		handler, err := NewHandler().
   847  			Logger(logger).
   848  			KeysFile(keysFile).
   849  			Public("^/api/clusters_mgmt/v1/public(/.*)?$").
   850  			Public("^/api/clusters_mgmt/v1/open(/.*)?$").
   851  			Next(next).
   852  			Build()
   853  		Expect(err).ToNot(HaveOccurred())
   854  
   855  		// Send a request for one of the public URLs:
   856  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/public", nil)
   857  		request.Header.Set("Authorization", "Bearer "+bearer)
   858  		recorder := httptest.NewRecorder()
   859  		handler.ServeHTTP(recorder, request)
   860  		Expect(recorder.Code).To(Equal(http.StatusOK))
   861  
   862  		// Send a request for another of the public URLs:
   863  		request = httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/open", nil)
   864  		request.Header.Set("Authorization", "Bearer "+bearer)
   865  		recorder = httptest.NewRecorder()
   866  		handler.ServeHTTP(recorder, request)
   867  		Expect(recorder.Code).To(Equal(http.StatusOK))
   868  	})
   869  
   870  	It("Doesn't pass ignored token to next handler for public URL", func() {
   871  		// Prepare the token:
   872  		bearer := MakeTokenString("Bearer", 1*time.Minute)
   873  
   874  		// Prepare the next handler:
   875  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   876  			actual, err := BearerFromContext(r.Context())
   877  			Expect(err).ToNot(HaveOccurred())
   878  			Expect(actual).To(BeEmpty())
   879  			w.WriteHeader(http.StatusOK)
   880  		})
   881  
   882  		// Prepare the handler:
   883  		handler, err := NewHandler().
   884  			Logger(logger).
   885  			KeysFile(keysFile).
   886  			Public("^/api/clusters_mgmt/v1/public(/.*)?$").
   887  			Next(next).
   888  			Build()
   889  		Expect(err).ToNot(HaveOccurred())
   890  
   891  		// Send the request:
   892  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/public", nil)
   893  		request.Header.Set("Authorization", "Bearer "+bearer)
   894  		recorder := httptest.NewRecorder()
   895  		handler.ServeHTTP(recorder, request)
   896  
   897  		// Verify the response:
   898  		Expect(recorder.Code).To(Equal(http.StatusOK))
   899  	})
   900  
   901  	It("Doesn't load insecure keys by default", func() {
   902  		var err error
   903  
   904  		// Prepare the server:
   905  		server, ca := MakeTCPTLSServer()
   906  		defer func() {
   907  			server.Close()
   908  			err = os.Remove(ca)
   909  			Expect(err).ToNot(HaveOccurred())
   910  		}()
   911  		server.AppendHandlers(
   912  			RespondWith(http.StatusOK, keysBytes),
   913  		)
   914  		server.SetAllowUnhandledRequests(true)
   915  
   916  		// Prepare the next handler:
   917  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   918  			w.WriteHeader(http.StatusOK)
   919  		})
   920  
   921  		// Prepare the token:
   922  		bearer := MakeTokenString("Bearer", 1*time.Minute)
   923  
   924  		// Prepare the handler:
   925  		handler, err := NewHandler().
   926  			Logger(logger).
   927  			KeysURL(server.URL()).
   928  			Next(next).
   929  			Build()
   930  		Expect(err).ToNot(HaveOccurred())
   931  
   932  		// Send the request:
   933  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   934  		request.Header.Set("Authorization", "Bearer "+bearer)
   935  		recorder := httptest.NewRecorder()
   936  		handler.ServeHTTP(recorder, request)
   937  
   938  		// Verify that the request is rejected:
   939  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
   940  	})
   941  
   942  	It("Loads insecure keys in insecure mode", func() {
   943  		var err error
   944  
   945  		// Prepare the server that will return the keys:
   946  		server, ca := MakeTCPTLSServer()
   947  		defer func() {
   948  			server.Close()
   949  			err = os.Remove(ca)
   950  			Expect(err).ToNot(HaveOccurred())
   951  		}()
   952  		server.AppendHandlers(
   953  			RespondWith(http.StatusOK, keysBytes),
   954  		)
   955  
   956  		// Prepare the next handler:
   957  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   958  			w.WriteHeader(http.StatusOK)
   959  		})
   960  
   961  		// Prepare the token:
   962  		bearer := MakeTokenString("Bearer", 1*time.Minute)
   963  
   964  		// Prepare the handler:
   965  		handler, err := NewHandler().
   966  			Logger(logger).
   967  			KeysURL(server.URL()).
   968  			KeysInsecure(true).
   969  			Next(next).
   970  			Build()
   971  		Expect(err).ToNot(HaveOccurred())
   972  
   973  		// Send the request:
   974  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
   975  		request.Header.Set("Authorization", "Bearer "+bearer)
   976  		recorder := httptest.NewRecorder()
   977  		handler.ServeHTTP(recorder, request)
   978  
   979  		// Verify that the request is rejected:
   980  		Expect(recorder.Code).To(Equal(http.StatusOK))
   981  	})
   982  
   983  	It("Returns the response of the next handler", func() {
   984  		// Prepare the token:
   985  		bearer := MakeTokenString("Bearer", 1*time.Minute)
   986  
   987  		// Prepare the next handler:
   988  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   989  			w.WriteHeader(http.StatusOK)
   990  			w.Header().Set("Content-Type", "application/json")
   991  			_, err := w.Write([]byte(`{
   992  				"myfield": "myvalue"
   993  			}`))
   994  			Expect(err).ToNot(HaveOccurred())
   995  		})
   996  
   997  		// Prepare the handler:
   998  		handler, err := NewHandler().
   999  			Logger(logger).
  1000  			KeysFile(keysFile).
  1001  			Next(next).
  1002  			Build()
  1003  		Expect(err).ToNot(HaveOccurred())
  1004  
  1005  		// Send a request:
  1006  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1007  		request.Header.Set("Authorization", "Bearer "+bearer)
  1008  		recorder := httptest.NewRecorder()
  1009  		handler.ServeHTTP(recorder, request)
  1010  
  1011  		// Verify the response:
  1012  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1013  		Expect(recorder.Header().Get("Content-Type")).To(Equal("application/json"))
  1014  		Expect(recorder.Body).To(MatchJSON(`{
  1015  			"myfield": "myvalue"
  1016  		}`))
  1017  	})
  1018  
  1019  	It("Accepts token if ACL is empty", func() {
  1020  		// Prepare the ACL:
  1021  		acl, err := os.CreateTemp("", "acl-*.yml")
  1022  		Expect(err).ToNot(HaveOccurred())
  1023  		_, err = acl.WriteString("")
  1024  		Expect(err).ToNot(HaveOccurred())
  1025  		defer func() {
  1026  			err := os.Remove(acl.Name())
  1027  			Expect(err).ToNot(HaveOccurred())
  1028  		}()
  1029  		err = acl.Close()
  1030  		Expect(err).ToNot(HaveOccurred())
  1031  
  1032  		// Prepare the next handler:
  1033  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1034  			w.WriteHeader(http.StatusOK)
  1035  		})
  1036  
  1037  		// Prepare the token:
  1038  		bearer := MakeTokenString("Bearer", 1*time.Minute)
  1039  
  1040  		// Prepare the handler:
  1041  		handler, err := NewHandler().
  1042  			Logger(logger).
  1043  			KeysFile(keysFile).
  1044  			Next(next).
  1045  			ACLFile(acl.Name()).
  1046  			Build()
  1047  		Expect(err).ToNot(HaveOccurred())
  1048  
  1049  		// Send the request:
  1050  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1051  		request.Header.Set("Authorization", "Bearer "+bearer)
  1052  		recorder := httptest.NewRecorder()
  1053  		handler.ServeHTTP(recorder, request)
  1054  
  1055  		// Verify the response:
  1056  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1057  	})
  1058  
  1059  	It("Accepts token that matches first ACL item", func() {
  1060  		// Prepare the ACL:
  1061  		acl, err := os.CreateTemp("", "acl-*.yml")
  1062  		Expect(err).ToNot(HaveOccurred())
  1063  		_, err = acl.WriteString(`
  1064                          - claim: email
  1065                            pattern: ^.*@example\.com$
  1066                          - claim: sub
  1067                            pattern: ^f:b3f7b485-7184-43c8-8169-37bd6d1fe4aa:myuser$
  1068                  `)
  1069  		Expect(err).ToNot(HaveOccurred())
  1070  		defer func() {
  1071  			err := os.Remove(acl.Name())
  1072  			Expect(err).ToNot(HaveOccurred())
  1073  		}()
  1074  		err = acl.Close()
  1075  		Expect(err).ToNot(HaveOccurred())
  1076  
  1077  		// Prepare the next handler:
  1078  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1079  			w.WriteHeader(http.StatusOK)
  1080  		})
  1081  
  1082  		// Prepare the token:
  1083  		token := MakeTokenObject(jwt.MapClaims{
  1084  			"typ":   "Bearer",
  1085  			"email": "jdoe@example.com",
  1086  		})
  1087  		bearer := token.Raw
  1088  
  1089  		// Prepare the handler:
  1090  		handler, err := NewHandler().
  1091  			Logger(logger).
  1092  			KeysFile(keysFile).
  1093  			Next(next).
  1094  			ACLFile(acl.Name()).
  1095  			Build()
  1096  		Expect(err).ToNot(HaveOccurred())
  1097  
  1098  		// Send the request:
  1099  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1100  		request.Header.Set("Authorization", "Bearer "+bearer)
  1101  		recorder := httptest.NewRecorder()
  1102  		handler.ServeHTTP(recorder, request)
  1103  
  1104  		// Verify the response:
  1105  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1106  	})
  1107  
  1108  	It("Accepts token that matches second ACL item", func() {
  1109  		// Prepare the ACL:
  1110  		acl, err := os.CreateTemp("", "acl-*.yml")
  1111  		Expect(err).ToNot(HaveOccurred())
  1112  		_, err = acl.WriteString(`
  1113                          - claim: email
  1114                            pattern: ^.*@example\.com$
  1115                          - claim: sub
  1116                            pattern: ^f:b3f7b485-7184-43c8-8169-37bd6d1fe4aa:myuser$
  1117                  `)
  1118  		Expect(err).ToNot(HaveOccurred())
  1119  		defer func() {
  1120  			err := os.Remove(acl.Name())
  1121  			Expect(err).ToNot(HaveOccurred())
  1122  		}()
  1123  		err = acl.Close()
  1124  		Expect(err).ToNot(HaveOccurred())
  1125  
  1126  		// Prepare the next handler:
  1127  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1128  			w.WriteHeader(http.StatusOK)
  1129  		})
  1130  
  1131  		// Prepare the token:
  1132  		token := MakeTokenObject(jwt.MapClaims{
  1133  			"typ": "Bearer",
  1134  			"sub": "f:b3f7b485-7184-43c8-8169-37bd6d1fe4aa:myuser",
  1135  		})
  1136  		bearer := token.Raw
  1137  
  1138  		// Prepare the handler:
  1139  		handler, err := NewHandler().
  1140  			Logger(logger).
  1141  			KeysFile(keysFile).
  1142  			Next(next).
  1143  			ACLFile(acl.Name()).
  1144  			Build()
  1145  		Expect(err).ToNot(HaveOccurred())
  1146  
  1147  		// Send the request:
  1148  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1149  		request.Header.Set("Authorization", "Bearer "+bearer)
  1150  		recorder := httptest.NewRecorder()
  1151  		handler.ServeHTTP(recorder, request)
  1152  
  1153  		// Verify the response:
  1154  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1155  	})
  1156  
  1157  	It("Accepts token that matches second ACL file", func() {
  1158  		// Prepare the first ACL:
  1159  		firstACL, err := os.CreateTemp("", "acl-*.yml")
  1160  		Expect(err).ToNot(HaveOccurred())
  1161  		_, err = firstACL.WriteString(`
  1162                          - claim: email
  1163                            pattern: ^.*@example\.com$
  1164                  `)
  1165  		Expect(err).ToNot(HaveOccurred())
  1166  		defer func() {
  1167  			err := os.Remove(firstACL.Name())
  1168  			Expect(err).ToNot(HaveOccurred())
  1169  		}()
  1170  		err = firstACL.Close()
  1171  		Expect(err).ToNot(HaveOccurred())
  1172  
  1173  		// Prepare the second ACL:
  1174  		secondACL, err := os.CreateTemp("", "acl-*.yml")
  1175  		Expect(err).ToNot(HaveOccurred())
  1176  		_, err = secondACL.WriteString(`
  1177                          - claim: sub
  1178                            pattern: ^f:b3f7b485-7184-43c8-8169-37bd6d1fe4aa:myuser$
  1179                  `)
  1180  		Expect(err).ToNot(HaveOccurred())
  1181  		defer func() {
  1182  			err := os.Remove(secondACL.Name())
  1183  			Expect(err).ToNot(HaveOccurred())
  1184  		}()
  1185  		err = secondACL.Close()
  1186  		Expect(err).ToNot(HaveOccurred())
  1187  
  1188  		// Prepare the next handler:
  1189  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1190  			w.WriteHeader(http.StatusOK)
  1191  		})
  1192  
  1193  		// Prepare the token:
  1194  		token := MakeTokenObject(jwt.MapClaims{
  1195  			"typ": "Bearer",
  1196  			"sub": "f:b3f7b485-7184-43c8-8169-37bd6d1fe4aa:myuser",
  1197  		})
  1198  		bearer := token.Raw
  1199  
  1200  		// Prepare the handler:
  1201  		handler, err := NewHandler().
  1202  			Logger(logger).
  1203  			KeysFile(keysFile).
  1204  			Next(next).
  1205  			ACLFile(firstACL.Name()).
  1206  			ACLFile(secondACL.Name()).
  1207  			Build()
  1208  		Expect(err).ToNot(HaveOccurred())
  1209  
  1210  		// Send the request:
  1211  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1212  		request.Header.Set("Authorization", "Bearer "+bearer)
  1213  		recorder := httptest.NewRecorder()
  1214  		handler.ServeHTTP(recorder, request)
  1215  
  1216  		// Verify the response:
  1217  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1218  	})
  1219  
  1220  	It("Rejects token that doesn't match the ACL", func() {
  1221  		// Prepare the ACL:
  1222  		acl, err := os.CreateTemp("", "acl-*.yml")
  1223  		Expect(err).ToNot(HaveOccurred())
  1224  		_, err = acl.WriteString(`
  1225                          - claim: email
  1226                            pattern: ^.*@example\.com$
  1227                          - claim: sub
  1228                            pattern: ^f:b3f7b485-7184-43c8-8169-37bd6d1fe4aa:myuser$
  1229                  `)
  1230  		Expect(err).ToNot(HaveOccurred())
  1231  		defer func() {
  1232  			err := os.Remove(acl.Name())
  1233  			Expect(err).ToNot(HaveOccurred())
  1234  		}()
  1235  		err = acl.Close()
  1236  		Expect(err).ToNot(HaveOccurred())
  1237  
  1238  		// Prepare the next handler, which should never be called:
  1239  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1240  			Expect(true).To(BeFalse())
  1241  			w.WriteHeader(http.StatusBadRequest)
  1242  		})
  1243  
  1244  		// Prepare the token:
  1245  		token := MakeTokenObject(jwt.MapClaims{
  1246  			"typ":   "Bearer",
  1247  			"email": "jdoe@hacker.com",
  1248  		})
  1249  		bearer := token.Raw
  1250  
  1251  		// Prepare the handler:
  1252  		handler, err := NewHandler().
  1253  			Logger(logger).
  1254  			KeysFile(keysFile).
  1255  			Next(next).
  1256  			ACLFile(acl.Name()).
  1257  			Build()
  1258  		Expect(err).ToNot(HaveOccurred())
  1259  
  1260  		// Send the request:
  1261  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1262  		request.Header.Set("Authorization", "Bearer "+bearer)
  1263  		recorder := httptest.NewRecorder()
  1264  		handler.ServeHTTP(recorder, request)
  1265  
  1266  		// Verify the response:
  1267  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1268  		Expect(recorder.Body).To(MatchJSON(`{
  1269  			"kind": "Error",
  1270  			"id": "401",
  1271  			"href": "/api/clusters_mgmt/v1/errors/401",
  1272  			"code": "CLUSTERS-MGMT-401",
  1273  			"reason": "Access denied"
  1274  		}`))
  1275  	})
  1276  
  1277  	It("Returns expected headers", func() {
  1278  		// Prepare the next handler, which should never be called:
  1279  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1280  			Expect(true).To(BeFalse())
  1281  			w.WriteHeader(http.StatusBadRequest)
  1282  		})
  1283  
  1284  		// Prepare the handler:
  1285  		handler, err := NewHandler().
  1286  			Logger(logger).
  1287  			KeysFile(keysFile).
  1288  			Next(next).
  1289  			Build()
  1290  		Expect(err).ToNot(HaveOccurred())
  1291  
  1292  		// Send the request:
  1293  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1294  		request.Header.Set("Authorization", "Bearer junk")
  1295  		recorder := httptest.NewRecorder()
  1296  		handler.ServeHTTP(recorder, request)
  1297  
  1298  		// Verify the response:
  1299  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1300  		header := recorder.Header().Get("WWW-Authenticate")
  1301  		Expect(header).To(Equal("Bearer realm=\"clusters_mgmt/v1\""))
  1302  	})
  1303  
  1304  	It("Supports multiple services and versions", func() {
  1305  		// Prepare the next handler, which should never be called:
  1306  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1307  			Expect(true).To(BeFalse())
  1308  			w.WriteHeader(http.StatusBadRequest)
  1309  		})
  1310  
  1311  		// Prepare the handler:
  1312  		handler, err := NewHandler().
  1313  			Logger(logger).
  1314  			KeysFile(keysFile).
  1315  			Next(next).
  1316  			Build()
  1317  		Expect(err).ToNot(HaveOccurred())
  1318  
  1319  		// Prepare the variables that we will use for the checks:
  1320  		var (
  1321  			request  *http.Request
  1322  			recorder *httptest.ResponseRecorder
  1323  		)
  1324  
  1325  		// Check a request for 'clusters_mgmt/v1':
  1326  		request = httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1327  		request.Header.Set("Authorization", "Bearer junk")
  1328  		recorder = httptest.NewRecorder()
  1329  		handler.ServeHTTP(recorder, request)
  1330  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1331  		Expect(recorder.Body).To(MatchJSON(`{
  1332  			"kind": "Error",
  1333  			"id": "401",
  1334  			"href": "/api/clusters_mgmt/v1/errors/401",
  1335  			"code": "CLUSTERS-MGMT-401",
  1336  			"reason": "Bearer token is malformed"
  1337  		}`))
  1338  
  1339  		// Check a request for 'clusters_mgmt/v2':
  1340  		request = httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v2/private", nil)
  1341  		request.Header.Set("Authorization", "Bearer junk")
  1342  		recorder = httptest.NewRecorder()
  1343  		handler.ServeHTTP(recorder, request)
  1344  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1345  		Expect(recorder.Body).To(MatchJSON(`{
  1346  			"kind": "Error",
  1347  			"id": "401",
  1348  			"href": "/api/clusters_mgmt/v2/errors/401",
  1349  			"code": "CLUSTERS-MGMT-401",
  1350  			"reason": "Bearer token is malformed"
  1351  		}`))
  1352  
  1353  		// Check a request for 'accounts_mgmt/v1':
  1354  		request = httptest.NewRequest(http.MethodGet, "/api/accounts_mgmt/v1/private", nil)
  1355  		request.Header.Set("Authorization", "Bearer junk")
  1356  		recorder = httptest.NewRecorder()
  1357  		handler.ServeHTTP(recorder, request)
  1358  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1359  		Expect(recorder.Body).To(MatchJSON(`{
  1360  			"kind": "Error",
  1361  			"id": "401",
  1362  			"href": "/api/accounts_mgmt/v1/errors/401",
  1363  			"code": "ACCOUNTS-MGMT-401",
  1364  			"reason": "Bearer token is malformed"
  1365  		}`))
  1366  
  1367  		// Check a request for 'accounts_mgmt/v2':
  1368  		request = httptest.NewRequest(http.MethodGet, "/api/accounts_mgmt/v2/private", nil)
  1369  		request.Header.Set("Authorization", "Bearer junk")
  1370  		recorder = httptest.NewRecorder()
  1371  		handler.ServeHTTP(recorder, request)
  1372  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1373  		Expect(recorder.Body).To(MatchJSON(`{
  1374  			"kind": "Error",
  1375  			"id": "401",
  1376  			"href": "/api/accounts_mgmt/v2/errors/401",
  1377  			"code": "ACCOUNTS-MGMT-401",
  1378  			"reason": "Bearer token is malformed"
  1379  		}`))
  1380  	})
  1381  
  1382  	It("Honours explicit service identifier", func() {
  1383  		// Prepare the next handler, which should never be called:
  1384  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1385  			Expect(true).To(BeFalse())
  1386  			w.WriteHeader(http.StatusBadRequest)
  1387  		})
  1388  
  1389  		// Prepare the handler:
  1390  		handler, err := NewHandler().
  1391  			Logger(logger).
  1392  			KeysFile(keysFile).
  1393  			Next(next).
  1394  			Service("my_service").
  1395  			Build()
  1396  		Expect(err).ToNot(HaveOccurred())
  1397  
  1398  		// Check that the response code contains the service identifier:
  1399  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1400  		request.Header.Set("Authorization", "Bearer junk")
  1401  		recorder := httptest.NewRecorder()
  1402  		handler.ServeHTTP(recorder, request)
  1403  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1404  		Expect(recorder.Body).To(MatchJSON(`{
  1405  			"kind": "Error",
  1406  			"id": "401",
  1407  			"href": "/api/clusters_mgmt/v1/errors/401",
  1408  			"code": "MY-SERVICE-401",
  1409  			"reason": "Bearer token is malformed"
  1410  		}`))
  1411  	})
  1412  
  1413  	It("Honours explicit error identifier", func() {
  1414  		// Prepare the next handler, which should never be called:
  1415  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1416  			Expect(true).To(BeFalse())
  1417  			w.WriteHeader(http.StatusBadRequest)
  1418  		})
  1419  
  1420  		// Prepare the handler:
  1421  		handler, err := NewHandler().
  1422  			Logger(logger).
  1423  			KeysFile(keysFile).
  1424  			Next(next).
  1425  			Error("123").
  1426  			Build()
  1427  		Expect(err).ToNot(HaveOccurred())
  1428  
  1429  		// Check that the response code contains the custom error identifier:
  1430  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1431  		request.Header.Set("Authorization", "Bearer junk")
  1432  		recorder := httptest.NewRecorder()
  1433  		handler.ServeHTTP(recorder, request)
  1434  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1435  		Expect(recorder.Body).To(MatchJSON(`{
  1436  			"kind": "Error",
  1437  			"id": "123",
  1438  			"href": "/api/clusters_mgmt/v1/errors/123",
  1439  			"code": "CLUSTERS-MGMT-123",
  1440  			"reason": "Bearer token is malformed"
  1441  		}`))
  1442  	})
  1443  
  1444  	It("Adds operation identifier", func() {
  1445  		// Prepare the next handler, which should never be called:
  1446  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1447  			Expect(true).To(BeFalse())
  1448  			w.WriteHeader(http.StatusBadRequest)
  1449  		})
  1450  
  1451  		// Prepare the handler:
  1452  		handler, err := NewHandler().
  1453  			Logger(logger).
  1454  			KeysFile(keysFile).
  1455  			Next(next).
  1456  			OperationID(func(r *http.Request) string {
  1457  				return r.Header.Get("X-Operation-ID")
  1458  			}).
  1459  			Build()
  1460  		Expect(err).ToNot(HaveOccurred())
  1461  
  1462  		// Check that the response code contains the operation identifier:
  1463  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1464  		request.Header.Set("Authorization", "Bearer junk")
  1465  		request.Header.Set("x-Operation-ID", "123")
  1466  		recorder := httptest.NewRecorder()
  1467  		handler.ServeHTTP(recorder, request)
  1468  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1469  		Expect(recorder.Body).To(MatchJSON(`{
  1470  			"kind": "Error",
  1471  			"id": "401",
  1472  			"href": "/api/clusters_mgmt/v1/errors/401",
  1473  			"code": "CLUSTERS-MGMT-401",
  1474  			"reason": "Bearer token is malformed",
  1475  			"operation_id": "123"
  1476  		}`))
  1477  	})
  1478  
  1479  	It("Accepts token expired within the configured tolerance", func() {
  1480  		// Prepare the next handler:
  1481  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1482  			w.WriteHeader(http.StatusOK)
  1483  		})
  1484  
  1485  		// Prepare a token that expired 5 minutes ago:
  1486  		bearer := MakeTokenString("Bearer", -5*time.Minute)
  1487  
  1488  		// Prepare a handler that tolerates tokens that expired up to 10 minutes ago:
  1489  		handler, err := NewHandler().
  1490  			Logger(logger).
  1491  			KeysFile(keysFile).
  1492  			Tolerance(10 * time.Minute).
  1493  			Next(next).
  1494  			Build()
  1495  		Expect(err).ToNot(HaveOccurred())
  1496  
  1497  		// Send the request:
  1498  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1499  		request.Header.Set("Authorization", "Bearer "+bearer)
  1500  		recorder := httptest.NewRecorder()
  1501  		handler.ServeHTTP(recorder, request)
  1502  
  1503  		// Verify the response:
  1504  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1505  	})
  1506  
  1507  	It("Rejects token expired outside the configured tolerance", func() {
  1508  		// Prepare the next handler:
  1509  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1510  			w.WriteHeader(http.StatusOK)
  1511  		})
  1512  
  1513  		// Prepare a token that expired 15 minutes ago:
  1514  		bearer := MakeTokenString("Bearer", -15*time.Minute)
  1515  
  1516  		// Prepare a handler that tolerates tokens that have expired up to 10 minutes ago:
  1517  		handler, err := NewHandler().
  1518  			Logger(logger).
  1519  			KeysFile(keysFile).
  1520  			Tolerance(10 * time.Minute).
  1521  			Next(next).
  1522  			Build()
  1523  		Expect(err).ToNot(HaveOccurred())
  1524  
  1525  		// Send the request:
  1526  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1527  		request.Header.Set("Authorization", "Bearer "+bearer)
  1528  		recorder := httptest.NewRecorder()
  1529  		handler.ServeHTTP(recorder, request)
  1530  
  1531  		// Verify the response:
  1532  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1533  	})
  1534  
  1535  	It("Accepts good token from cookie", func() {
  1536  		// Prepare the next handler:
  1537  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1538  			w.WriteHeader(http.StatusOK)
  1539  		})
  1540  
  1541  		// Prepare the token:
  1542  		bearer := MakeTokenString("Bearer", 15*time.Minute)
  1543  
  1544  		// Prepare the handler:
  1545  		handler, err := NewHandler().
  1546  			Logger(logger).
  1547  			KeysFile(keysFile).
  1548  			Next(next).
  1549  			Build()
  1550  		Expect(err).ToNot(HaveOccurred())
  1551  
  1552  		// Send the request:
  1553  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1554  		request.AddCookie(&http.Cookie{
  1555  			Name:  "cs_jwt",
  1556  			Value: bearer,
  1557  		})
  1558  		recorder := httptest.NewRecorder()
  1559  		handler.ServeHTTP(recorder, request)
  1560  
  1561  		// Verify the response:
  1562  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1563  	})
  1564  
  1565  	It("Rejects bad token from cookie", func() {
  1566  		// Prepare the next handler:
  1567  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1568  			w.WriteHeader(http.StatusOK)
  1569  		})
  1570  
  1571  		// Prepare the handler:
  1572  		handler, err := NewHandler().
  1573  			Logger(logger).
  1574  			KeysFile(keysFile).
  1575  			Next(next).
  1576  			Build()
  1577  		Expect(err).ToNot(HaveOccurred())
  1578  
  1579  		// Send the request:
  1580  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1581  		request.AddCookie(&http.Cookie{
  1582  			Name:  "cs_jwt",
  1583  			Value: "junk",
  1584  		})
  1585  		recorder := httptest.NewRecorder()
  1586  		handler.ServeHTTP(recorder, request)
  1587  
  1588  		// Verify the response:
  1589  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1590  	})
  1591  
  1592  	It("Ignores cookie when header present", func() {
  1593  		// Prepare the next handler:
  1594  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1595  			w.WriteHeader(http.StatusOK)
  1596  		})
  1597  
  1598  		// Prepare the token:
  1599  		bearer := MakeTokenString("Bearer", 15*time.Minute)
  1600  
  1601  		// Prepare the handler:
  1602  		handler, err := NewHandler().
  1603  			Logger(logger).
  1604  			KeysFile(keysFile).
  1605  			Next(next).
  1606  			Build()
  1607  		Expect(err).ToNot(HaveOccurred())
  1608  
  1609  		// Send the request:
  1610  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1611  		request.Header.Set("Authorization", "Bearer "+bearer)
  1612  		request.AddCookie(&http.Cookie{
  1613  			Name:  "cs_jwt",
  1614  			Value: "junk",
  1615  		})
  1616  		recorder := httptest.NewRecorder()
  1617  		handler.ServeHTTP(recorder, request)
  1618  
  1619  		// Verify the response:
  1620  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1621  	})
  1622  
  1623  	It("Honours custom cookie", func() {
  1624  		// Prepare the next handler:
  1625  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1626  			w.WriteHeader(http.StatusOK)
  1627  		})
  1628  
  1629  		// Prepare the token:
  1630  		bearer := MakeTokenString("Bearer", 15*time.Minute)
  1631  
  1632  		// Prepare the handler:
  1633  		handler, err := NewHandler().
  1634  			Logger(logger).
  1635  			KeysFile(keysFile).
  1636  			Cookie("my_cookie").
  1637  			Next(next).
  1638  			Build()
  1639  		Expect(err).ToNot(HaveOccurred())
  1640  
  1641  		// Send the request:
  1642  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1643  		request.AddCookie(&http.Cookie{
  1644  			Name:  "my_cookie",
  1645  			Value: bearer,
  1646  		})
  1647  		recorder := httptest.NewRecorder()
  1648  		handler.ServeHTTP(recorder, request)
  1649  
  1650  		// Verify the response:
  1651  		Expect(recorder.Code).To(Equal(http.StatusOK))
  1652  	})
  1653  
  1654  	It("Ignores default cookie when custom cookie is specified", func() {
  1655  		// Prepare the next handler:
  1656  		next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1657  			w.WriteHeader(http.StatusOK)
  1658  		})
  1659  
  1660  		// Prepare the token:
  1661  		bearer := MakeTokenString("Bearer", 15*time.Minute)
  1662  
  1663  		// Prepare the handler:
  1664  		handler, err := NewHandler().
  1665  			Logger(logger).
  1666  			KeysFile(keysFile).
  1667  			Cookie("my_cookie").
  1668  			Next(next).
  1669  			Build()
  1670  		Expect(err).ToNot(HaveOccurred())
  1671  
  1672  		// Send the request:
  1673  		request := httptest.NewRequest(http.MethodGet, "/api/clusters_mgmt/v1/private", nil)
  1674  		request.AddCookie(&http.Cookie{
  1675  			Name:  "cs_jwt",
  1676  			Value: bearer,
  1677  		})
  1678  		recorder := httptest.NewRecorder()
  1679  		handler.ServeHTTP(recorder, request)
  1680  
  1681  		// Verify the response:
  1682  		Expect(recorder.Code).To(Equal(http.StatusUnauthorized))
  1683  	})
  1684  })