github.com/BTBurke/caddy-jwt@v3.7.1+incompatible/jwt_test.go (about)

     1  package jwt
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"os"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"io/ioutil"
    13  
    14  	jwt "github.com/dgrijalva/jwt-go"
    15  	"github.com/caddyserver/caddy/caddyhttp/httpserver"
    16  	. "github.com/onsi/ginkgo"
    17  	. "github.com/onsi/gomega"
    18  )
    19  
    20  const (
    21  	validToken     = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"
    22  	malformedToken = "loremIpsum"
    23  	rsaPublicKey   = `-----BEGIN PUBLIC KEY-----
    24  MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx8HkixKMKDI43bBcL5TxhNsTy
    25  4qbZW+LMzSazcFmICITg/c3BbDyCS88VO6hqPhfLzQsNbaZeKKqxQfVudhYQI2cX
    26  9ID2IuYxw3M8vazffhiJjgKVXnNaGdUCnKVFKVPxklwVztxVE8tYmfN0cvAeNafc
    27  KPMSbZEZEqQeFfkafQIDAQAB
    28  -----END PUBLIC KEY-----
    29  `
    30  	rsaPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
    31  MIICXgIBAAKBgQCx8HkixKMKDI43bBcL5TxhNsTy4qbZW+LMzSazcFmICITg/c3B
    32  bDyCS88VO6hqPhfLzQsNbaZeKKqxQfVudhYQI2cX9ID2IuYxw3M8vazffhiJjgKV
    33  XnNaGdUCnKVFKVPxklwVztxVE8tYmfN0cvAeNafcKPMSbZEZEqQeFfkafQIDAQAB
    34  AoGBAI1NRDTK6BnTzJ/QUyDcIi2ku5ORTyPuZtVx2FjIUCDJexPcGKeP1yE1KDZZ
    35  UK1Fr8nkgvFf8Kx3KM1obokQdwV3QXTtENIaLoq3OTzmDihGmvrSqCvfWPQNF/Wn
    36  qxcMedY3z/u4RqHW5Gects0K6RDWNua8QV0W6jazRFzcfcKhAkEA6tSQiOmjUUQz
    37  +IKNr0BU+r127uNuly9t5w6Umqd4i9eYzRZRaNeokFCn7qOr/D70hMJynHLYr3sZ
    38  KtBQUsFf5QJBAMH6+THDtPfFiB8Qtz67ucQq2DwWWUjCVFLd3rqMiRqZ7mJNEv+C
    39  YOusKbw54UHCD5bgORYC5HXVg2hzBYj2trkCQCA/oLmsnCkE3L4774kppIHqkvKr
    40  ePx6HvWkIvQ6G2vY57sCXZuwQg3PhcBX6b5yRtIUgfjKLMeseABRKzayJ6ECQQCe
    41  KcCdrvETRWBj1AFViUNCi5ycAazzAmA24OkGOihgJDqWtDlVVD0qa8nry1W7hDup
    42  zVE+fUVCPsFSnNZagq8hAkEA4tOFUKxqEDg+QXaJbFXiUTj9BMDUlEGTqGS/becS
    43  99L5HGoSkzGQazoqD6bA6ZQwF+gUN1LweweK7LLcnZsVFg==
    44  -----END RSA PRIVATE KEY-----
    45  `
    46  	ecdsaPublicKey = `-----BEGIN PUBLIC KEY-----
    47  MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBa7NUN5FTTN0snJpIxpljP3vZ/gQA
    48  X7yBZpGBdHxPAKcV1dkxUPZeaqJKS5UsGL+Z5QzaaionFVddNNTiZxFZVmoAJxcF
    49  lW5lqXQXg4iJ6yNd7dVrNDSvH6CyVNME9lhu4sDXsYEofjidtnNsSQ4cLIiW3q2J
    50  6pF7NtHApTtl/GKDPoY=
    51  -----END PUBLIC KEY-----
    52  `
    53  	ecdsaPrivateKey = `-----BEGIN EC PRIVATE KEY-----
    54  MIHcAgEBBEIB1QVyei7HRoi+sTQUj5RrvRiqZ5/xUSzqCm5hm/Xco5B/i2gZID/B
    55  J48fw0IFpKcWX4DY8to2wQWI6vYH0Up+ekWgBwYFK4EEACOhgYkDgYYABAFrs1Q3
    56  kVNM3SycmkjGmWM/e9n+BABfvIFmkYF0fE8ApxXV2TFQ9l5qokpLlSwYv5nlDNpq
    57  KicVV1001OJnEVlWagAnFwWVbmWpdBeDiInrI13t1Ws0NK8foLJU0wT2WG7iwNex
    58  gSh+OJ22c2xJDhwsiJberYnqkXs20cClO2X8YoM+hg==
    59  -----END EC PRIVATE KEY-----
    60  `
    61  )
    62  
    63  func TestCaddyJwt(t *testing.T) {
    64  	RegisterFailHandler(Fail)
    65  	RunSpecs(t, "CaddyJWT Suite")
    66  }
    67  
    68  func passThruHandler(w http.ResponseWriter, r *http.Request) (int, error) {
    69  	// copy received headers back into response so they can be inspected
    70  	for head, val := range r.Header {
    71  		w.Header().Add(head, val[0])
    72  	}
    73  	return http.StatusOK, nil
    74  }
    75  
    76  func genToken(secret string, claims map[string]interface{}) string {
    77  	token := jwt.New(jwt.SigningMethodHS256)
    78  	token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
    79  
    80  	for claim, value := range claims {
    81  		token.Claims.(jwt.MapClaims)[claim] = value
    82  	}
    83  	validToken, err := token.SignedString([]byte(secret))
    84  	if err != nil {
    85  		Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
    86  	}
    87  	return validToken
    88  }
    89  
    90  func genRSAToken(privatekey string, claims map[string]interface{}) string {
    91  	token := jwt.New(jwt.SigningMethodRS256)
    92  	token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
    93  
    94  	for claim, value := range claims {
    95  		token.Claims.(jwt.MapClaims)[claim] = value
    96  	}
    97  	pemKey, _ := jwt.ParseRSAPrivateKeyFromPEM([]byte(privatekey))
    98  
    99  	validToken, err := token.SignedString(pemKey)
   100  	if err != nil {
   101  		Fail("failed constructing RSA token")
   102  	}
   103  	return validToken
   104  }
   105  
   106  func setSecretAndGetEnv(value string) *HmacKeyBackend {
   107  	backend := setSecretAndTryGetEnv(value)
   108  	if backend == nil {
   109  		Fail("unexpected error constructing backends")
   110  	}
   111  	return backend
   112  }
   113  
   114  func setSecretAndTryGetEnv(value string) *HmacKeyBackend {
   115  	if err := os.Setenv(ENV_SECRET, value); err != nil {
   116  		Fail("unexpected error setting JWT_SECRET")
   117  	}
   118  	os.Unsetenv(ENV_PUBLIC_KEY)
   119  	backends, err := NewDefaultKeyBackends()
   120  	if err != nil {
   121  		Fail(fmt.Sprintf("unexpected error constructing backends: %s", err))
   122  	}
   123  	if len(backends) != 1 {
   124  		return nil
   125  	}
   126  	return backends[0].(*HmacKeyBackend)
   127  }
   128  
   129  func setPublicKeyAndGetEnv(value string) *PublicKeyBackend {
   130  	backend := setPublicKeyAndTryGetEnv(value)
   131  	if backend == nil {
   132  		Fail("unexpected error constructing backends")
   133  	}
   134  	return backend
   135  }
   136  
   137  func setPublicKeyAndTryGetEnv(value string) *PublicKeyBackend {
   138  	if err := os.Setenv(ENV_PUBLIC_KEY, value); err != nil {
   139  		Fail("unexpected error setting JWT_PUBLIC_KEY")
   140  	}
   141  	os.Unsetenv(ENV_SECRET)
   142  	backends, err := NewDefaultKeyBackends()
   143  	if err != nil {
   144  		Fail(fmt.Sprintf("unexpected error constructing backends: %s", err))
   145  	}
   146  	if len(backends) != 1 {
   147  		return nil
   148  	}
   149  	return backends[0].(*PublicKeyBackend)
   150  }
   151  
   152  var _ = Describe("Auth", func() {
   153  	AfterEach(func() {
   154  		os.Unsetenv(ENV_PUBLIC_KEY)
   155  		os.Unsetenv(ENV_SECRET)
   156  	})
   157  	Describe("Use environment to get secrets", func() {
   158  
   159  		It("should get the JWT secret from the environment JWT_SECRET", func() {
   160  			backend := setSecretAndGetEnv("secret")
   161  			Expect(backend.secret).To(Equal([]byte("secret")))
   162  		})
   163  
   164  		It("should return an error JWT_SECRET not set", func() {
   165  			backend := setSecretAndTryGetEnv("")
   166  			Expect(backend).To(BeNil())
   167  		})
   168  
   169  		It("should find RSA key material stored on disk", func() {
   170  			pemKey, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(rsaPublicKey))
   171  			keyfile, err := ioutil.TempFile(os.TempDir(), "testkey")
   172  			if err != nil {
   173  				Fail("Unexpected error creating temporary key file")
   174  			}
   175  			defer os.Remove(keyfile.Name())
   176  			if _, err := keyfile.Write([]byte(rsaPublicKey)); err != nil {
   177  				Fail("Unexpected error writing temporary key file")
   178  			}
   179  			if err := keyfile.Close(); err != nil {
   180  				Fail("Unexpected error closing temporary key file")
   181  			}
   182  			backend, err := NewLazyPublicKeyFileBackend(keyfile.Name())
   183  			if err != nil {
   184  				Fail(err.Error())
   185  			}
   186  			if err := backend.loadIfRequired(); err != nil {
   187  				Fail(err.Error())
   188  			}
   189  			Expect(backend.publicKey).To(Equal(pemKey))
   190  			Expect(backend.filename).To(Equal(keyfile.Name()))
   191  		})
   192  
   193  		It("should find ECDSA key material stored on disk", func() {
   194  			pemKey, _ := jwt.ParseECPublicKeyFromPEM([]byte(ecdsaPublicKey))
   195  			keyfile, err := ioutil.TempFile(os.TempDir(), "testkey")
   196  			if err != nil {
   197  				Fail("Unexpected error creating temporary key file")
   198  			}
   199  			defer os.Remove(keyfile.Name())
   200  			if _, err := keyfile.Write([]byte(ecdsaPublicKey)); err != nil {
   201  				Fail("Unexpected error writing temporary key file")
   202  			}
   203  			if err := keyfile.Close(); err != nil {
   204  				Fail("Unexpected error closing temporary key file")
   205  			}
   206  			backend, err := NewLazyPublicKeyFileBackend(keyfile.Name())
   207  			if err != nil {
   208  				Fail(err.Error())
   209  			}
   210  			if err := backend.loadIfRequired(); err != nil {
   211  				Fail(err.Error())
   212  			}
   213  			Expect(backend.publicKey).To(Equal(pemKey))
   214  			Expect(backend.filename).To(Equal(keyfile.Name()))
   215  		})
   216  
   217  		It("should find HMAC key material stored on disk and invalidate cache if file changes", func() {
   218  			secret1 := []byte("secret1")
   219  			secret2 := []byte("secret2")
   220  
   221  			keyfile, err := ioutil.TempFile(os.TempDir(), "testkey")
   222  			if err != nil {
   223  				Fail("Unexpected error creating temporary key file")
   224  			}
   225  			defer os.Remove(keyfile.Name())
   226  
   227  			if _, err := keyfile.Write(secret1); err != nil {
   228  				Fail("Unexpected error writing temporary key file")
   229  			}
   230  			if err := keyfile.Close(); err != nil {
   231  				Fail("Unexpected error closing temporary key file")
   232  			}
   233  
   234  			backend, err := NewLazyHmacKeyBackend(keyfile.Name())
   235  			if err != nil {
   236  				Fail(err.Error())
   237  			}
   238  			if err := backend.loadIfRequired(); err != nil {
   239  				Fail(err.Error())
   240  			}
   241  			Expect(backend.secret).To(Equal(secret1))
   242  			Expect(backend.filename).To(Equal(keyfile.Name()))
   243  
   244  			// write new value and invalidate cache after short timeout to allow modinfo time to change
   245  			time.Sleep(20 * time.Millisecond)
   246  			if err := ioutil.WriteFile(keyfile.Name(), secret2, os.ModePerm); err != nil {
   247  				Fail("Unexpected error overwriting keyfile in cache invalidation test")
   248  			}
   249  
   250  			if err := backend.loadIfRequired(); err != nil {
   251  				Fail(err.Error())
   252  			}
   253  			Expect(backend.secret).To(Equal(secret2))
   254  			Expect(backend.filename).To(Equal(keyfile.Name()))
   255  		})
   256  
   257  		It("should detect invalid configurations of auth backends", func() {
   258  			os.Unsetenv("JWT_PUBLIC_KEY")
   259  			os.Unsetenv("JWT_SECRET")
   260  			backends, err := NewDefaultKeyBackends()
   261  			if err != nil {
   262  				Fail(err.Error())
   263  			}
   264  			Expect(len(backends)).To(Equal(0))
   265  		})
   266  	})
   267  
   268  	Describe("Validate flatten map function", func() {
   269  
   270  		listMap := map[string]interface{}{"context": map[string]interface{}{"user": map[string]interface{}{"roles": []string{"admin", "user"}}}}
   271  		myMap := map[string]interface{}{"context": map[string]interface{}{"user": map[string]interface{}{"username": "foobar"}}}
   272  
   273  		It("Should flatten map with dots", func() {
   274  			result, err := Flatten(myMap, "", DotStyle)
   275  			if err != nil {
   276  				panic(err)
   277  			}
   278  			expectedMap := map[string]interface{}{"context.user.username": "foobar"}
   279  			Expect(result).To(Equal(expectedMap))
   280  		})
   281  		It("Should flatten map and leave slices as is", func() {
   282  			result, err := Flatten(listMap, "", DotStyle)
   283  			if err != nil {
   284  				panic(err)
   285  			}
   286  			expectedMap := map[string]interface{}{"context.user.roles": []string{"admin", "user"}}
   287  			Expect(result).To(Equal(expectedMap))
   288  		})
   289  	})
   290  
   291  	Describe("Find tokens in the request with a default token source config", func() {
   292  		// Empty list should trigger the use of the default config.
   293  		// This also tests each token source type individually.
   294  		emptyTssList := []TokenSource{}
   295  		It("should return the token if set in the Auhorization header", func() {
   296  			req, _ := http.NewRequest("GET", "/testing", nil)
   297  			req.Header.Set("Authorization", strings.Join([]string{"Bearer", validToken}, " "))
   298  			token, err := ExtractToken(emptyTssList, req)
   299  			Expect(err).To(BeNil())
   300  			Expect(token).To(Equal(validToken))
   301  		})
   302  
   303  		It("should return the token if set in a cookie", func() {
   304  			req, _ := http.NewRequest("GET", "/testing", nil)
   305  			req.AddCookie(&http.Cookie{Name: "jwt_token", Value: validToken})
   306  			token, err := ExtractToken(emptyTssList, req)
   307  			Expect(err).To(BeNil())
   308  			Expect(token).To(Equal(validToken))
   309  		})
   310  
   311  		It("should return the token if set as query parameter", func() {
   312  			url := strings.Join([]string{"/testing?token=", validToken}, "")
   313  			req, _ := http.NewRequest("GET", url, nil)
   314  			token, err := ExtractToken(emptyTssList, req)
   315  			Expect(err).To(BeNil())
   316  			Expect(token).To(Equal(validToken))
   317  		})
   318  	})
   319  
   320  	Describe("Find tokens in the request with a custom token source config", func() {
   321  		It("should return the token from the first source that finds it in the request", func() {
   322  			config := []TokenSource{
   323  				&QueryTokenSource{
   324  					ParamName: "custom_param",
   325  				},
   326  				&CookieTokenSource{
   327  					CookieName: "custom_jwt_token",
   328  				},
   329  				&HeaderTokenSource{
   330  					HeaderName: "Bearer",
   331  				},
   332  			}
   333  			// These should be ignored as their names don't match.
   334  			url := strings.Join([]string{"/testing?token=", malformedToken}, "")
   335  			req, _ := http.NewRequest("GET", url, nil)
   336  			req.AddCookie(&http.Cookie{Name: "jwt_token", Value: malformedToken})
   337  			// This should be ignored as it is the last in the config list.
   338  			req.Header.Set("Authorization", strings.Join([]string{"Bearer", malformedToken}, " "))
   339  			// This should be extracted.
   340  			req.AddCookie(&http.Cookie{Name: "custom_jwt_token", Value: validToken})
   341  			token, err := ExtractToken(config, req)
   342  			Expect(err).To(BeNil())
   343  			Expect(token).To(Equal(validToken))
   344  		})
   345  	})
   346  
   347  	Describe("Validate tokens in accordance with the JWT standard", func() {
   348  
   349  		It("should validate a correctly formed token", func() {
   350  			backend := setSecretAndGetEnv("secret")
   351  			token := jwt.New(jwt.SigningMethodHS256)
   352  			token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
   353  			sToken, err := token.SignedString([]byte("secret"))
   354  			if err != nil {
   355  				Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   356  			}
   357  			vToken, err := ValidateToken(sToken, backend)
   358  
   359  			Expect(err).To(BeNil())
   360  			Expect(vToken.Valid).To(Equal(true))
   361  		})
   362  
   363  		It("should validate a correctly formed RSA token", func() {
   364  			backend := setPublicKeyAndGetEnv(rsaPublicKey)
   365  			token := jwt.New(jwt.SigningMethodRS256)
   366  			token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
   367  
   368  			secret, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(rsaPrivateKey))
   369  			if err != nil {
   370  				Fail(fmt.Sprintf("unexpected error constructing private key: %s", err))
   371  			}
   372  			sToken, err := token.SignedString(secret)
   373  			if err != nil {
   374  				Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   375  			}
   376  
   377  			vToken, err := ValidateToken(sToken, backend)
   378  
   379  			Expect(err).To(BeNil())
   380  			Expect(vToken.Valid).To(Equal(true))
   381  		})
   382  
   383  		It("should validate a correctly formed ECDSA token", func() {
   384  			backend := setPublicKeyAndGetEnv(ecdsaPublicKey)
   385  			token := jwt.New(jwt.SigningMethodES512)
   386  			token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
   387  
   388  			secret, err := jwt.ParseECPrivateKeyFromPEM([]byte(ecdsaPrivateKey))
   389  			if err != nil {
   390  				Fail(fmt.Sprintf("unexpected error constructing private key: %s", err))
   391  			}
   392  			sToken, err := token.SignedString(secret)
   393  			if err != nil {
   394  				Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   395  			}
   396  
   397  			vToken, err := ValidateToken(sToken, backend)
   398  
   399  			Expect(err).To(BeNil())
   400  			Expect(vToken.Valid).To(Equal(true))
   401  		})
   402  
   403  		It("should not validate a incorrectly formed token", func() {
   404  			backend := setSecretAndGetEnv("secret")
   405  			token := jwt.New(jwt.SigningMethodHS256)
   406  			token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
   407  			sToken, err := token.SignedString([]byte("notsecret"))
   408  			if err != nil {
   409  				Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   410  			}
   411  
   412  			vToken, err := ValidateToken(sToken, backend)
   413  
   414  			Expect(err).To(HaveOccurred())
   415  			Expect(vToken).To(BeNil())
   416  		})
   417  
   418  		It("should not validate a malformed token", func() {
   419  			backend := setSecretAndGetEnv("secret")
   420  
   421  			vToken, err := ValidateToken(malformedToken, backend)
   422  
   423  			Expect(err).To(HaveOccurred())
   424  			Expect(vToken).To(BeNil())
   425  		})
   426  
   427  		It("should not validate a token with an expired timestamp", func() {
   428  			backend := setSecretAndGetEnv("secret")
   429  			token := jwt.New(jwt.SigningMethodHS256)
   430  			token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * -1).Unix()
   431  			sToken, err := token.SignedString([]byte("secret"))
   432  			if err != nil {
   433  				Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   434  			}
   435  
   436  			vToken, err := ValidateToken(sToken, backend)
   437  
   438  			Expect(err).To(HaveOccurred())
   439  			Expect(vToken).To(BeNil())
   440  		})
   441  
   442  		It("should not allow JWT with algorithm none", func() {
   443  			backend := setSecretAndGetEnv("secret")
   444  			token := jwt.New(jwt.SigningMethodHS256)
   445  			token.Header["alg"] = "none"
   446  			token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
   447  			sToken, err := token.SignedString([]byte("secret"))
   448  			if err != nil {
   449  				Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   450  			}
   451  
   452  			vToken, err := ValidateToken(sToken, backend)
   453  
   454  			Expect(err).To(HaveOccurred())
   455  			Expect(vToken).To(BeNil())
   456  		})
   457  	})
   458  	Describe("Redirect on access deny works", func() {
   459  		It("return 303 when a redirect is configured and access denied", func() {
   460  			req, err := http.NewRequest("GET", "/testing", nil)
   461  
   462  			rec := httptest.NewRecorder()
   463  			rw := Auth{
   464  				Rules: []Rule{{Path: "/testing", Redirect: "/login"}},
   465  			}
   466  			result, err := rw.ServeHTTP(rec, req)
   467  			if err != nil {
   468  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   469  			}
   470  
   471  			Expect(result).To(Equal(http.StatusSeeOther))
   472  			Expect(rec.Result().StatusCode).To(Equal(http.StatusSeeOther))
   473  			Expect(rec.Result().Header.Get("Location")).To(Equal("/login"))
   474  		})
   475  		It("variables in location value are replaced", func() {
   476  			req, err := http.NewRequest("GET", "/testing", nil)
   477  
   478  			rec := httptest.NewRecorder()
   479  			rw := Auth{
   480  				Rules: []Rule{{Path: "/testing", Redirect: "/login?backTo={rewrite_uri}"}},
   481  			}
   482  			result, err := rw.ServeHTTP(rec, req)
   483  			if err != nil {
   484  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   485  			}
   486  
   487  			Expect(result).To(Equal(http.StatusSeeOther))
   488  			Expect(rec.Result().StatusCode).To(Equal(http.StatusSeeOther))
   489  			Expect(rec.Result().Header.Get("Location")).To(Equal("/login?backTo=/testing"))
   490  		})
   491  	})
   492  	Describe("Function correctly as an authorization middleware for malformed paths", func() {
   493  		It("return 401 when no authorization header and the path is protected (malformed path - 1st level)", func() {
   494  			rw := Auth{
   495  				Next: httpserver.HandlerFunc(passThruHandler),
   496  				Rules: []Rule{
   497  					Rule{Path: "/"},
   498  				},
   499  				Realm: "testing.com",
   500  			}
   501  			req, err := http.NewRequest("GET", "//testing", nil)
   502  
   503  			rec := httptest.NewRecorder()
   504  			result, err := rw.ServeHTTP(rec, req)
   505  			if err != nil {
   506  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   507  			}
   508  
   509  			Expect(result).To(Equal(http.StatusUnauthorized))
   510  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   511  		})
   512  		It("return 401 when no authorization header and the path is protected (malformed path - root level)", func() {
   513  			rw := Auth{
   514  				Next: httpserver.HandlerFunc(passThruHandler),
   515  				Rules: []Rule{
   516  					Rule{Path: "/"},
   517  				},
   518  				Realm: "testing.com",
   519  			}
   520  			req, err := http.NewRequest("GET", "//", nil)
   521  
   522  			rec := httptest.NewRecorder()
   523  			result, err := rw.ServeHTTP(rec, req)
   524  			if err != nil {
   525  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   526  			}
   527  
   528  			Expect(result).To(Equal(http.StatusUnauthorized))
   529  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   530  		})
   531  
   532  		It("return 401 when no authorization header and the path is protected (malformed path - 2nd level)", func() {
   533  			rw := Auth{
   534  				Next: httpserver.HandlerFunc(passThruHandler),
   535  				Rules: []Rule{
   536  					Rule{Path: "/testing/test"},
   537  				},
   538  				Realm: "testing.com",
   539  			}
   540  			req, err := http.NewRequest("GET", "/testing//test", nil)
   541  
   542  			rec := httptest.NewRecorder()
   543  			result, err := rw.ServeHTTP(rec, req)
   544  			if err != nil {
   545  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   546  			}
   547  
   548  			Expect(result).To(Equal(http.StatusUnauthorized))
   549  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   550  		})
   551  
   552  		It("return 401 when no authorization header and the path is protected (malformed path - 2nd of nested)", func() {
   553  			rw := Auth{
   554  				Next: httpserver.HandlerFunc(passThruHandler),
   555  				Rules: []Rule{
   556  					Rule{Path: "/testing/test/secret"},
   557  				},
   558  				Realm: "testing.com",
   559  			}
   560  			req, err := http.NewRequest("GET", "/testing//test/secret", nil)
   561  
   562  			rec := httptest.NewRecorder()
   563  			result, err := rw.ServeHTTP(rec, req)
   564  			if err != nil {
   565  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   566  			}
   567  
   568  			Expect(result).To(Equal(http.StatusUnauthorized))
   569  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   570  		})
   571  		It("return 401 when no authorization header and the path is protected (malformed path - 3rd level)", func() {
   572  			rw := Auth{
   573  				Next: httpserver.HandlerFunc(passThruHandler),
   574  				Rules: []Rule{
   575  					Rule{Path: "/testing/test/secret"},
   576  				},
   577  				Realm: "testing.com",
   578  			}
   579  			req, err := http.NewRequest("GET", "/testing/test//secret", nil)
   580  
   581  			rec := httptest.NewRecorder()
   582  			result, err := rw.ServeHTTP(rec, req)
   583  			if err != nil {
   584  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   585  			}
   586  
   587  			Expect(result).To(Equal(http.StatusUnauthorized))
   588  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   589  		})
   590  
   591  	})
   592  	Describe("Function correctly as an authorization middleware", func() {
   593  		backend := setSecretAndGetEnv("secret")
   594  		rw := Auth{
   595  			Next: httpserver.HandlerFunc(passThruHandler),
   596  			Rules: []Rule{
   597  				Rule{Path: "/testing", ExceptedPaths: []string{"/testing/excepted"}, KeyBackends: []KeyBackend{backend}},
   598  			},
   599  			Realm: "testing.com",
   600  		}
   601  		token := jwt.New(jwt.SigningMethodHS256)
   602  		token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
   603  		token.Claims.(jwt.MapClaims)["user"] = "test"
   604  		token.Claims.(jwt.MapClaims)["int32"] = int32(10)
   605  		token.Claims.(jwt.MapClaims)["float32"] = float32(3.14159)
   606  		token.Claims.(jwt.MapClaims)["float64"] = float64(3.14159)
   607  		token.Claims.(jwt.MapClaims)["bool"] = true
   608  		token.Claims.(jwt.MapClaims)["list"] = []string{"foo", "bar", "bazz"}
   609  		token.Claims.(jwt.MapClaims)["http://test.com/path"] = "true"
   610  
   611  		validToken, err := token.SignedString([]byte("secret"))
   612  		if err != nil {
   613  			Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   614  		}
   615  
   616  		invalidToken, err := token.SignedString([]byte("notsecret"))
   617  		if err != nil {
   618  			Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   619  		}
   620  
   621  		It("return 401 when no authorization header and the path is protected", func() {
   622  			req, err := http.NewRequest("GET", "/testing", nil)
   623  
   624  			rec := httptest.NewRecorder()
   625  			result, err := rw.ServeHTTP(rec, req)
   626  			if err != nil {
   627  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   628  			}
   629  
   630  			Expect(result).To(Equal(http.StatusUnauthorized))
   631  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   632  		})
   633  
   634  		It("return 401 when no authorization header and the path is protected (malformed path)", func() {
   635  			req, err := http.NewRequest("GET", "//testing", nil)
   636  
   637  			rec := httptest.NewRecorder()
   638  			result, err := rw.ServeHTTP(rec, req)
   639  			if err != nil {
   640  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   641  			}
   642  
   643  			Expect(result).To(Equal(http.StatusUnauthorized))
   644  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   645  		})
   646  
   647  		It("return 401 when no token and the path is protected", func() {
   648  			req, err := http.NewRequest("GET", "/testing", nil)
   649  			req.Header.Set("Authorization", strings.Join([]string{"Basic", "QWxhZGRpbjpvcGVuIHNlc2FtZQ=="}, " "))
   650  
   651  			rec := httptest.NewRecorder()
   652  			result, err := rw.ServeHTTP(rec, req)
   653  			if err != nil {
   654  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   655  			}
   656  
   657  			Expect(result).To(Equal(http.StatusUnauthorized))
   658  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   659  		})
   660  
   661  		It("return 401 when the token is not valid and the path is protected", func() {
   662  			req, err := http.NewRequest("GET", "/testing", nil)
   663  			req.Header.Set("Authorization", strings.Join([]string{"Bearer", invalidToken}, " "))
   664  
   665  			rec := httptest.NewRecorder()
   666  			result, err := rw.ServeHTTP(rec, req)
   667  			if err != nil {
   668  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   669  			}
   670  
   671  			Expect(result).To(Equal(http.StatusUnauthorized))
   672  			Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"invalid_token\""))
   673  		})
   674  
   675  		It("allow valid requests to continue to next handler", func() {
   676  			req, err := http.NewRequest("GET", "/testing", nil)
   677  			req.Header.Set("Authorization", strings.Join([]string{"Bearer", validToken}, " "))
   678  
   679  			rec := httptest.NewRecorder()
   680  			result, err := rw.ServeHTTP(rec, req)
   681  			if err != nil {
   682  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   683  			}
   684  
   685  			Expect(result).To(Equal(http.StatusOK))
   686  		})
   687  
   688  		It("allow OPTIONS requests to continue to next handler", func() {
   689  			req, err := http.NewRequest("OPTIONS", "/testing", nil)
   690  
   691  			rec := httptest.NewRecorder()
   692  			result, err := rw.ServeHTTP(rec, req)
   693  			if err != nil {
   694  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   695  			}
   696  
   697  			Expect(result).To(Equal(http.StatusOK))
   698  		})
   699  
   700  		It("allow unprotected requests to continue to next handler", func() {
   701  			req, err := http.NewRequest("GET", "/unprotected", nil)
   702  
   703  			rec := httptest.NewRecorder()
   704  			result, err := rw.ServeHTTP(rec, req)
   705  			if err != nil {
   706  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   707  			}
   708  
   709  			Expect(result).To(Equal(http.StatusOK))
   710  		})
   711  
   712  		It("allow excepted path requests to continue to next handler", func() {
   713  			req, err := http.NewRequest("GET", "/testing/excepted", nil)
   714  
   715  			rec := httptest.NewRecorder()
   716  			result, err := rw.ServeHTTP(rec, req)
   717  			if err != nil {
   718  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   719  			}
   720  
   721  			Expect(result).To(Equal(http.StatusOK))
   722  		})
   723  
   724  		It("set claims as individual headers", func() {
   725  			req, err := http.NewRequest("GET", "/testing", nil)
   726  			req.Header.Set("Authorization", strings.Join([]string{"Bearer", validToken}, " "))
   727  
   728  			rec := httptest.NewRecorder()
   729  			result, err := rw.ServeHTTP(rec, req)
   730  			if err != nil {
   731  				Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   732  			}
   733  
   734  			Expect(result).To(Equal(http.StatusOK))
   735  			expectedHeaders := map[string]string{
   736  				"Token-Claim-User":                       "test",
   737  				"Token-Claim-Bool":                       "true",
   738  				"Token-Claim-Float32":                    "3.14159",
   739  				"Token-Claim-Float64":                    "3.14159",
   740  				"Token-Claim-Int32":                      "10",
   741  				"Token-Claim-List":                       "foo,bar,bazz",
   742  				"Token-Claim-Http:%2F%2Ftest.com%2Fpath": "true",
   743  			}
   744  			returnedHeaders := rec.Header()
   745  			for head, value := range expectedHeaders {
   746  				val, ok := returnedHeaders[head]
   747  				if !ok {
   748  					Fail(fmt.Sprintf("expected header not in response: %v. Have: %v", head, returnedHeaders))
   749  				}
   750  				Expect(val[0]).To(Equal(value))
   751  			}
   752  
   753  		})
   754  		Describe("Strip headers when set", func() {
   755  			backend := setSecretAndGetEnv("secret")
   756  			rw := Auth{
   757  				Next: httpserver.HandlerFunc(passThruHandler),
   758  				Rules: []Rule{
   759  					Rule{Path: "/testing", ExceptedPaths: []string{"/testing/excepted"}, StripHeader: true, KeyBackends: []KeyBackend{backend}},
   760  				},
   761  				Realm: "testing.com",
   762  			}
   763  			token := jwt.New(jwt.SigningMethodHS256)
   764  			token.Claims.(jwt.MapClaims)["exp"] = time.Now().Add(time.Hour * 1).Unix()
   765  			token.Claims.(jwt.MapClaims)["user"] = "test"
   766  			token.Claims.(jwt.MapClaims)["int32"] = int32(10)
   767  			token.Claims.(jwt.MapClaims)["float32"] = float32(3.14159)
   768  			token.Claims.(jwt.MapClaims)["float64"] = float64(3.14159)
   769  			token.Claims.(jwt.MapClaims)["bool"] = true
   770  			token.Claims.(jwt.MapClaims)["list"] = []string{"foo", "bar", "bazz"}
   771  			token.Claims.(jwt.MapClaims)["http://test.com/path.me"] = "true"
   772  
   773  			validToken, err := token.SignedString([]byte("secret"))
   774  			if err != nil {
   775  				Fail(fmt.Sprintf("unexpected error constructing token: %s", err))
   776  			}
   777  
   778  			It("set claims as individual headers, and strips if necessary", func() {
   779  				req, err := http.NewRequest("GET", "/testing", nil)
   780  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", validToken}, " "))
   781  
   782  				rec := httptest.NewRecorder()
   783  				result, err := rw.ServeHTTP(rec, req)
   784  				if err != nil {
   785  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   786  				}
   787  
   788  				Expect(result).To(Equal(http.StatusOK))
   789  				expectedHeaders := map[string]string{
   790  					"Token-Claim-User":    "test",
   791  					"Token-Claim-Bool":    "true",
   792  					"Token-Claim-Float32": "3.14159",
   793  					"Token-Claim-Float64": "3.14159",
   794  					"Token-Claim-Int32":   "10",
   795  					"Token-Claim-List":    "foo,bar,bazz",
   796  					"Token-Claim-Path.me": "true",
   797  				}
   798  				returnedHeaders := rec.Header()
   799  				for head, value := range expectedHeaders {
   800  					val, ok := returnedHeaders[head]
   801  					if !ok {
   802  						Fail(fmt.Sprintf("expected header not in response: %v. Have: %v", head, returnedHeaders))
   803  					}
   804  					Expect(val[0]).To(Equal(value))
   805  				}
   806  
   807  			})
   808  		})
   809  		Describe("Function correctly as an authorization middleware for complex access rules", func() {
   810  			backend := setSecretAndGetEnv("secret")
   811  			tokenUser := genToken("secret", map[string]interface{}{"user": "test", "role": "member"})
   812  			tokenNotUser := genToken("secret", map[string]interface{}{"user": "bad"})
   813  			tokenAdmin := genToken("secret", map[string]interface{}{"role": "admin"})
   814  			accessRuleAllowUser := AccessRule{Authorize: ALLOW,
   815  				Claim: "user",
   816  				Value: "test",
   817  			}
   818  			accessRuleAllowRole := AccessRule{Authorize: ALLOW,
   819  				Claim: "role",
   820  				Value: "admin",
   821  			}
   822  			accessRuleDenyRole := AccessRule{Authorize: DENY,
   823  				Claim: "role",
   824  				Value: "member",
   825  			}
   826  			ruleAllowUser := Rule{Path: "/testing", AccessRules: []AccessRule{accessRuleAllowUser}, KeyBackends: []KeyBackend{backend}}
   827  			ruleDenyRole := Rule{Path: "/testing", AccessRules: []AccessRule{accessRuleDenyRole}, KeyBackends: []KeyBackend{backend}}
   828  			ruleAllowRoleAllowUser := []Rule{Rule{Path: "/testing", AccessRules: []AccessRule{accessRuleAllowRole, accessRuleAllowUser}, KeyBackends: []KeyBackend{backend}}}
   829  			ruleDenyRoleAllowUser := []Rule{Rule{Path: "/testing", AccessRules: []AccessRule{accessRuleDenyRole, accessRuleAllowUser}, KeyBackends: []KeyBackend{backend}}}
   830  
   831  			It("should allow authorization based on a specific claim value", func() {
   832  				rw := Auth{
   833  					Next:  httpserver.HandlerFunc(passThruHandler),
   834  					Rules: []Rule{ruleAllowUser},
   835  				}
   836  
   837  				req, err := http.NewRequest("GET", "/testing", nil)
   838  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", tokenUser}, " "))
   839  
   840  				rec := httptest.NewRecorder()
   841  				result, err := rw.ServeHTTP(rec, req)
   842  				if err != nil {
   843  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   844  				}
   845  
   846  				Expect(result).To(Equal(http.StatusOK))
   847  			})
   848  			It("should deny authorization based on a specific claim value that doesnt match", func() {
   849  				rw := Auth{
   850  					Next:  httpserver.HandlerFunc(passThruHandler),
   851  					Rules: []Rule{ruleAllowUser},
   852  					Realm: "testing.com",
   853  				}
   854  
   855  				req, err := http.NewRequest("GET", "/testing", nil)
   856  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", tokenNotUser}, " "))
   857  
   858  				rec := httptest.NewRecorder()
   859  				result, err := rw.ServeHTTP(rec, req)
   860  				if err != nil {
   861  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   862  				}
   863  
   864  				Expect(result).To(Equal(http.StatusForbidden))
   865  				Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"insufficient_scope\""))
   866  			})
   867  			It("should correctly apply rules in order with multiple ALLOWs", func() {
   868  				// tests situation where user is denied based on wrong role
   869  				// but subsequent allow based on username is ok
   870  				rw := Auth{
   871  					Next:  httpserver.HandlerFunc(passThruHandler),
   872  					Rules: ruleAllowRoleAllowUser,
   873  				}
   874  
   875  				req, err := http.NewRequest("GET", "/testing", nil)
   876  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", tokenUser}, " "))
   877  
   878  				rec := httptest.NewRecorder()
   879  				result, err := rw.ServeHTTP(rec, req)
   880  				if err != nil {
   881  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   882  				}
   883  
   884  				Expect(result).To(Equal(http.StatusOK))
   885  			})
   886  			It("should correctly apply rules in order with a DENY then ALLOW", func() {
   887  				// test situation where default deny for a particular role
   888  				// subsequent rule based on user ok
   889  				rw := Auth{
   890  					Next:  httpserver.HandlerFunc(passThruHandler),
   891  					Rules: ruleDenyRoleAllowUser,
   892  				}
   893  
   894  				req, err := http.NewRequest("GET", "/testing", nil)
   895  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", tokenUser}, " "))
   896  
   897  				rec := httptest.NewRecorder()
   898  				result, err := rw.ServeHTTP(rec, req)
   899  				if err != nil {
   900  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   901  				}
   902  
   903  				Expect(result).To(Equal(http.StatusOK))
   904  			})
   905  
   906  			It("should correctly deny based on specific match", func() {
   907  				// tests situation where user is denied based on wrong role
   908  				// but subsequent allow based on username is ok
   909  				rw := Auth{
   910  					Next:  httpserver.HandlerFunc(passThruHandler),
   911  					Rules: []Rule{ruleDenyRole},
   912  					Realm: "testing.com",
   913  				}
   914  
   915  				req, err := http.NewRequest("GET", "/testing", nil)
   916  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", tokenUser}, " "))
   917  
   918  				rec := httptest.NewRecorder()
   919  				result, err := rw.ServeHTTP(rec, req)
   920  				if err != nil {
   921  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   922  				}
   923  
   924  				Expect(result).To(Equal(http.StatusForbidden))
   925  				Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"insufficient_scope\""))
   926  			})
   927  
   928  			It("should allow based on no match to DENY", func() {
   929  				// tests situation where user is denied based on wrong role
   930  				// but subsequent allow based on username is ok
   931  				rw := Auth{
   932  					Next:  httpserver.HandlerFunc(passThruHandler),
   933  					Rules: []Rule{ruleDenyRole},
   934  				}
   935  
   936  				req, err := http.NewRequest("GET", "/testing", nil)
   937  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", tokenAdmin}, " "))
   938  
   939  				rec := httptest.NewRecorder()
   940  				result, err := rw.ServeHTTP(rec, req)
   941  				if err != nil {
   942  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   943  				}
   944  
   945  				Expect(result).To(Equal(http.StatusOK))
   946  			})
   947  		})
   948  		Describe("Function correctly as an authorization middleware for list types", func() {
   949  
   950  			tokenGroups := genToken("secret", map[string]interface{}{"group": []string{"admin", "user"}})
   951  			tokenGroupsOperator := genToken("secret", map[string]interface{}{"group": []string{"operator"}})
   952  			ruleAllowUser := Rule{Path: "/testing", AccessRules: []AccessRule{
   953  				AccessRule{Authorize: ALLOW,
   954  					Claim: "group",
   955  					Value: "admin",
   956  				},
   957  				AccessRule{Authorize: DENY,
   958  					Claim: "group",
   959  					Value: "operator",
   960  				},
   961  			}, KeyBackends: []KeyBackend{backend}}
   962  			BeforeEach(func() {
   963  				if err := os.Setenv("JWT_SECRET", "secret"); err != nil {
   964  					Fail("Could not set environment secret")
   965  				}
   966  				if err := os.Setenv("JWT_PUBLIC_KEY", ""); err != nil {
   967  					Fail("Could not unset secret")
   968  				}
   969  			})
   970  
   971  			It("should allow claim values, which are part of a list", func() {
   972  				rw := Auth{
   973  					Next:  httpserver.HandlerFunc(passThruHandler),
   974  					Rules: []Rule{ruleAllowUser},
   975  				}
   976  
   977  				req, err := http.NewRequest("GET", "/testing", nil)
   978  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", tokenGroups}, " "))
   979  
   980  				rec := httptest.NewRecorder()
   981  				result, err := rw.ServeHTTP(rec, req)
   982  				if err != nil {
   983  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
   984  				}
   985  
   986  				Expect(result).To(Equal(http.StatusOK))
   987  			})
   988  			It("should deny claim values, which are part of a list", func() {
   989  				rw := Auth{
   990  					Next:  httpserver.HandlerFunc(passThruHandler),
   991  					Rules: []Rule{ruleAllowUser},
   992  					Realm: "testing.com",
   993  				}
   994  
   995  				req, err := http.NewRequest("GET", "/testing", nil)
   996  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", tokenGroupsOperator}, " "))
   997  
   998  				rec := httptest.NewRecorder()
   999  				result, err := rw.ServeHTTP(rec, req)
  1000  				if err != nil {
  1001  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
  1002  				}
  1003  
  1004  				Expect(result).To(Equal(http.StatusForbidden))
  1005  				Expect(rec.Result().Header.Get("WWW-Authenticate")).To(Equal("Bearer realm=\"testing.com\",error=\"insufficient_scope\""))
  1006  			})
  1007  		})
  1008  
  1009  		Describe("Prevent spoofing of claims headers", func() {
  1010  			It("should remove spoofed claims with no JWT provided", func() {
  1011  				rw := Auth{
  1012  					Next:  httpserver.HandlerFunc(passThruHandler),
  1013  					Rules: []Rule{{Path: "/testing", Passthrough: true}},
  1014  				}
  1015  				req, err := http.NewRequest("GET", "/testing", nil)
  1016  				req.Header.Set("Token-Claim-Spoofed", "spoof")
  1017  
  1018  				rec := httptest.NewRecorder()
  1019  				result, err := rw.ServeHTTP(rec, req)
  1020  				if err != nil {
  1021  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
  1022  				}
  1023  
  1024  				Expect(result).To(Equal(http.StatusOK))
  1025  				Expect(rec.Result().Header.Get("Token-Claim-Spoofed")).To(Equal(""))
  1026  			})
  1027  
  1028  			It("should remove spoofed claims with valid token provided", func() {
  1029  				rw := Auth{
  1030  					Next:  httpserver.HandlerFunc(passThruHandler),
  1031  					Rules: []Rule{{Path: "/testing", Passthrough: true}},
  1032  				}
  1033  				req, err := http.NewRequest("GET", "/testing", nil)
  1034  				req.Header.Set("Token-Claim-Spoofed", "spoof")
  1035  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", validToken}, " "))
  1036  
  1037  				rec := httptest.NewRecorder()
  1038  				result, err := rw.ServeHTTP(rec, req)
  1039  				if err != nil {
  1040  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
  1041  				}
  1042  
  1043  				Expect(result).To(Equal(http.StatusOK))
  1044  				Expect(rec.Result().Header.Get("Token-Claim-Spoofed")).To(Equal(""))
  1045  			})
  1046  
  1047  			It("should remove spoofed claims with invalid token provided", func() {
  1048  				rw := Auth{
  1049  					Next:  httpserver.HandlerFunc(passThruHandler),
  1050  					Rules: []Rule{{Path: "/testing", Passthrough: true}},
  1051  				}
  1052  				req, err := http.NewRequest("GET", "/testing", nil)
  1053  				req.Header.Set("Token-Claim-Spoofed", "spoof")
  1054  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", "foo"}, " "))
  1055  
  1056  				rec := httptest.NewRecorder()
  1057  				result, err := rw.ServeHTTP(rec, req)
  1058  				if err != nil {
  1059  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
  1060  				}
  1061  
  1062  				Expect(result).To(Equal(http.StatusOK))
  1063  				Expect(rec.Result().Header.Get("Token-Claim-Spoofed")).To(Equal(""))
  1064  			})
  1065  		})
  1066  
  1067  		Describe("Handle multiple keyfiles correctly", func() {
  1068  			It("should allow access when one of the keyfiles matches", func() {
  1069  				key1, err := createKeyFile(rsaPublicKey)
  1070  				if err != nil {
  1071  					Fail(fmt.Sprintf("unexpected error creating key file: %s", err))
  1072  				}
  1073  				backend1, err := NewLazyPublicKeyFileBackend(key1)
  1074  				if err != nil {
  1075  					Fail(err.Error())
  1076  				}
  1077  				defer os.Remove(key1)
  1078  				key2, err := createKeyFile("notvalidkey")
  1079  				if err != nil {
  1080  					Fail(fmt.Sprintf("unexpected error creating key file: %s", err))
  1081  				}
  1082  				backend2, err := NewLazyPublicKeyFileBackend(key2)
  1083  				if err != nil {
  1084  					Fail(err.Error())
  1085  				}
  1086  				defer os.Remove(key2)
  1087  
  1088  				token := genRSAToken(rsaPrivateKey, map[string]interface{}{"test": "test"})
  1089  
  1090  				rw := Auth{
  1091  					Next:  httpserver.HandlerFunc(passThruHandler),
  1092  					Rules: []Rule{{Path: "/testing", KeyBackends: []KeyBackend{backend1, backend2}}},
  1093  				}
  1094  				req, err := http.NewRequest("GET", "/testing", nil)
  1095  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", token}, " "))
  1096  
  1097  				rec := httptest.NewRecorder()
  1098  				result, err := rw.ServeHTTP(rec, req)
  1099  				if err != nil {
  1100  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
  1101  				}
  1102  
  1103  				Expect(result).To(Equal(http.StatusOK))
  1104  			})
  1105  			It("should allow access when one of the keyfiles matches in any order", func() {
  1106  				key1, err := createKeyFile(rsaPublicKey)
  1107  				if err != nil {
  1108  					Fail(fmt.Sprintf("unexpected error creating key file: %s", err))
  1109  				}
  1110  				backend1, err := NewLazyPublicKeyFileBackend(key1)
  1111  				if err != nil {
  1112  					Fail(err.Error())
  1113  				}
  1114  				defer os.Remove(key1)
  1115  				key2, err := createKeyFile("notvalidkey")
  1116  				if err != nil {
  1117  					Fail(fmt.Sprintf("unexpected error creating key file: %s", err))
  1118  				}
  1119  				backend2, err := NewLazyPublicKeyFileBackend(key2)
  1120  				if err != nil {
  1121  					Fail(err.Error())
  1122  				}
  1123  				defer os.Remove(key2)
  1124  
  1125  				token := genRSAToken(rsaPrivateKey, map[string]interface{}{"test": "test"})
  1126  
  1127  				rw := Auth{
  1128  					Next:  httpserver.HandlerFunc(passThruHandler),
  1129  					Rules: []Rule{{Path: "/testing", KeyBackends: []KeyBackend{backend2, backend2, backend2, backend1}}},
  1130  				}
  1131  				req, err := http.NewRequest("GET", "/testing", nil)
  1132  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", token}, " "))
  1133  
  1134  				rec := httptest.NewRecorder()
  1135  				result, err := rw.ServeHTTP(rec, req)
  1136  				if err != nil {
  1137  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
  1138  				}
  1139  
  1140  				Expect(result).To(Equal(http.StatusOK))
  1141  			})
  1142  			It("should deny access when all keyfiles dont validate", func() {
  1143  				key2, err := createKeyFile("notvalidkey")
  1144  				if err != nil {
  1145  					Fail(fmt.Sprintf("unexpected error creating key file: %s", err))
  1146  				}
  1147  				backend2, err := NewLazyPublicKeyFileBackend(key2)
  1148  				if err != nil {
  1149  					Fail(err.Error())
  1150  				}
  1151  				defer os.Remove(key2)
  1152  
  1153  				token := genRSAToken(rsaPrivateKey, map[string]interface{}{"test": "test"})
  1154  
  1155  				rw := Auth{
  1156  					Next:  httpserver.HandlerFunc(passThruHandler),
  1157  					Rules: []Rule{{Path: "/testing", KeyBackends: []KeyBackend{backend2, backend2, backend2}}},
  1158  				}
  1159  				req, err := http.NewRequest("GET", "/testing", nil)
  1160  				req.Header.Set("Authorization", strings.Join([]string{"Bearer", token}, " "))
  1161  
  1162  				rec := httptest.NewRecorder()
  1163  				result, err := rw.ServeHTTP(rec, req)
  1164  				if err != nil {
  1165  					Fail(fmt.Sprintf("unexpected error constructing server: %s", err))
  1166  				}
  1167  
  1168  				Expect(result).To(Equal(http.StatusUnauthorized))
  1169  			})
  1170  		})
  1171  	})
  1172  
  1173  })
  1174  
  1175  func createKeyFile(key string) (string, error) {
  1176  	f, err := ioutil.TempFile("", "jwt")
  1177  	if err != nil {
  1178  		return "", err
  1179  	}
  1180  	if _, err := f.Write([]byte(key)); err != nil {
  1181  		return "", err
  1182  	}
  1183  	if err := f.Close(); err != nil {
  1184  		return "", err
  1185  	}
  1186  	return f.Name(), nil
  1187  }