1 package keyfunc_test
2
3 import (
4 "bytes"
5 "context"
6 "crypto/ecdsa"
7 "crypto/ed25519"
8 "crypto/rsa"
9 _ "embed"
10 "errors"
11 "fmt"
12 "net/http"
13 "net/http/httptest"
14 "os"
15 "path/filepath"
16 "strings"
17 "sync"
18 "testing"
19 "time"
20
21 "github.com/golang-jwt/jwt/v5"
22
23 "github.com/MicahParks/keyfunc/v2"
24 )
25
26 const (
27
28 emptyJWKSJSON = `{"keys":[]}`
29
30
31 logFmt = "%s\nError: %s"
32
33
34 jwksFilePath = "/example_jwks.json"
35
36
37 tokenUseEnc = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImtpZFdpdGhCYWRVc2UiLCJ0eXAiOiJKV1QifQ.eyJmb28iOiJiYXIifQ.NKUjRgfqNZNCckL2yyiZc0ot_-BxtwYiknrILmsSnNapkOB32gMfRPTyc_j-UsIqw19FrDSBNk31blxSW40X3ubXp56hpwbcqE0nj9EvDyZoUWmtMl6pXIGPnTK5y-rNgS8i1IeeejNAQDYe8LOtCw_jE8CpOW5MBZzxdwjntPHGCWu4FCgrBu1ugth20B7WnuCHETa0xQ2NvXIX0W54JDbk_hdWTqjP4Bo7BvcGB6-5xZ1AaiiXjnOOuBrIMwTrZ-wtdTOjmSaWrcH94A8wDk263fSkhRLjM77d5IljIILT4a6nRHVSsgBfhblYevtX6NWBgllvQ_Hr_uuaT_b15A"
38 )
39
40 var (
41
42
43 jwksJSON string
44 )
45
46
47
48 func TestInvalidServer(t *testing.T) {
49 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
50 _, err := w.Write(nil)
51 if err != nil {
52 t.Fatalf(logFmt, "Failed to write empty response.", err)
53 }
54 }))
55 defer server.Close()
56
57 testingRefreshErrorHandler := func(err error) {
58 t.Fatalf(logFmt, "Unhandled JWKS error.", err)
59 }
60
61 refreshInterval := time.Second
62 options := keyfunc.Options{
63 RefreshInterval: refreshInterval,
64 RefreshErrorHandler: testingRefreshErrorHandler,
65 }
66
67 _, err := keyfunc.Get(server.URL, options)
68 if err == nil {
69 t.Fatalf("Creation of *keyfunc.JWKS with invalid server must fail.")
70 }
71 }
72
73
74 func TestJWKS(t *testing.T) {
75 tempDir, err := os.MkdirTemp("", "*")
76 if err != nil {
77 t.Fatalf(logFmt, "Failed to create a temporary directory.", err)
78 }
79 defer func() {
80 err = os.RemoveAll(tempDir)
81 if err != nil {
82 t.Fatalf(logFmt, "Failed to remove temporary directory.", err)
83 }
84 }()
85
86 jwksFile := filepath.Join(tempDir, jwksFilePath)
87
88 err = os.WriteFile(jwksFile, []byte(jwksJSON), 0600)
89 if err != nil {
90 t.Fatalf(logFmt, "Failed to write JWKS file to temporary directory.", err)
91 }
92
93 server := httptest.NewServer(http.FileServer(http.Dir(tempDir)))
94 defer server.Close()
95
96 testingRefreshInterval := time.Second
97 testingRateLimit := time.Millisecond * 500
98 testingRefreshTimeout := time.Second
99 testingRefreshErrorHandler := func(err error) {
100 panic(fmt.Sprintf(logFmt, "Unhandled JWKS error.", err))
101 }
102
103 jwksURL := server.URL + jwksFilePath
104
105 options := []keyfunc.Options{
106 {},
107 {
108 Client: http.DefaultClient,
109 },
110 {
111 Ctx: context.Background(),
112 },
113 {
114 RefreshErrorHandler: testingRefreshErrorHandler,
115 },
116 {
117 RefreshInterval: testingRefreshInterval,
118 },
119 {
120 RefreshRateLimit: testingRateLimit,
121 },
122 {
123 RefreshTimeout: testingRefreshTimeout,
124 },
125 }
126
127 for _, opts := range options {
128 jwks, err := keyfunc.Get(jwksURL, opts)
129 if err != nil {
130 t.Fatalf(logFmt, "Failed to get JWKS from testing URL.", err)
131 }
132
133 testCases := []struct {
134 token string
135 }{
136 {""},
137 {"eyJhbGciOiJFUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJDR3QwWldTNExjNWZhaUtTZGkwdFUwZmpDQWR2R1JPUVJHVTlpUjd0VjBBIn0.eyJleHAiOjE2MTU0MDY4NjEsImlhdCI6MTYxNTQwNjgwMSwianRpIjoiYWVmOWQ5YjItN2EyYy00ZmQ4LTk4MzktODRiMzQ0Y2VmYzZhIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.iQ77QGoPDNjR2oWLu3zT851mswP8J-h_nrGhs3fpa_tFB3FT1deKPGkjef9JOTYFI-CIVxdCFtW3KODOaw9Nrw"},
138 {"eyJhbGciOiJFUzM4NCIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJUVkFBZXQ2M08zeHlfS0s2X2J4Vkl1N1JhM196MXdsQjU0M0Zid2k1VmFVIn0.eyJleHAiOjE2MTU0MDY4OTAsImlhdCI6MTYxNTQwNjgzMCwianRpIjoiYWNhNDU4NTItZTE0ZS00MjgxLTljZTQtN2ZiNzVkMTg1MWJmIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.oHFT-RvbNNT6p4_tIoZzr4IS88bZqy20cJhF6FZCIXALZ2dppoOjutanPVxzuLC5axG3P71noVghNUF8X44bTShP1boLrlde2QKmj5GxDR-oNEb9ES_zC10rZ5I76CwR"},
139 {"eyJhbGciOiJFUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlYkp4bm05QjNRREJsakI1WEpXRXU3MnF4NkJhd0RhTUFod3o0YUtQa1EwIn0.eyJleHAiOjE2MTU0MDY5MDksImlhdCI6MTYxNTQwNjg0OSwianRpIjoiMjBhMGI1MTMtN2E4My00OGQ2LThmNDgtZmQ3NDc1N2Y4OWRiIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.AdR59BCvGlctL5BMgXlpJBBToKTPG4SVa-oJKBqE7qxvTSBwAQM5D3uUc2toM3NAUERSMKOLTJfzfxenNRixrDMnAcrdFHgEY10vsDp6uqA7NMUevHE5f7jiAVK1talXS9O41IEnR2DKbAG0GgjIA2WHLhUgftG2uNN8LMKI2QSbLCfM"},
140 {"eyJhbGciOiJFUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlYkp4bm05QjNRREJsakI1WEpXRXU3MnF4NkJhd0RhTUFod3o0YUtQa1EwIn0.eyJleHAiOjE2MTU0MDY5MDksImlhdCI6MTYxNTQwNjg0OSwianRpIjoiMjBhMGI1MTMtN2E4My00OGQ2LThmNDgtZmQ3NDc1N2Y4OWRiIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.AdR59BCvGlctL5BMgXlpJBBToKTPG4SVa-oJKBqE7qxvTSBwAQM5D3uUc2toM3NAUERSMKOLTJfzfxenNRixrDMnAcrdFHgEY10vsDp6uqA7NMUevHE5f7jiAVK1talXS9O41IEnR2DKbAG0GgjIA2WHLhUgftG2uNN8LMKI2QSbLCfM"},
141 {"eyJhbGciOiJQUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6WGV3MFVKMWg2UTRDQ2NkXzl3eE16dmNwNWNFQmlmSDBLV3JDejJLeXhjIn0.eyJleHAiOjE2MTU0MDY5NjIsImlhdCI6MTYxNTQwNjkwMiwianRpIjoiNWIyZGY5N2EtNDQyOS00ZTA0LWFkMzgtOWZmNjVlZDU2MTZjIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.tafkUwLXm3lyyqJHwAGwFPN3IO0rCrESJnVcIuI1KHPSKogn5DgWqR3B9QCvqIusqlxhGW7MvOhG-9dIy62ciKGQFDRFA9T46TMm9t8O80TnhYTB8ImX90xYuf6E74k1RiqRVcubFWKHWlhKjqXMM4dD2l8VwqL45E6kHpNDvzvILKAfrMgm0vHsfi6v5rf32HLp6Ox1PvpKrM1kDgsdXm6scgAGJCTbOQB2Pzc-i8cyFPeuckbeL4zbM3-Odqc-eI-3pXevMzUB608J3fRpQK1W053kU7iG9RFC-5nBwvrBlN4Lff_X1R3JBLkFcA0wJeFYtIFnMm6lVbA7nwa0Xg"},
142 {"eyJhbGciOiJQUzM4NCIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMeDFGbWF5UDJZQnR4YXFTMVNLSlJKR2lYUktudzJvdjVXbVlJTUctQkxFIn0.eyJleHAiOjE2MTU0MDY5ODIsImlhdCI6MTYxNTQwNjkyMiwianRpIjoiMGY2NGJjYTktYjU4OC00MWFhLWFkNDEtMmFmZDM2OGRmNTFkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.Rxrq41AxbWKIQHWv-Tkb7rqwel3sKT_R_AGvn9mPIHqhw1m7nsQWcL9t2a_8MI2hCwgWtYdgTF1xxBNmb2IW3CZkML5nGfcRrFvNaBHd3UQEqbFKZgnIX29h5VoxekyiwFaGD-0RXL83jF7k39hytEzTatwoVjZ-frga0KFl-nLce3OwncRXVCGmxoFzUsyu9TQFS2Mm_p0AMX1y1MAX1JmLC3WFhH3BohhRqpzBtjSfs_f46nE1-HKjqZ1ERrAc2fmiVJjmG7sT702JRuuzrgUpHlMy2juBG4DkVcMlj4neJUmCD1vZyZBRggfaIxNkwUhHtmS2Cp9tOcwNu47tSg"},
143 {"eyJhbGciOiJQUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ0VzZhZTdUb21FNl8yam9vTS1zZjlOXzZsV2c3SE50YVFYckRzRWxCek00In0.eyJleHAiOjE2MTU0MDcwMDUsImlhdCI6MTYxNTQwNjk0NSwianRpIjoiYzJmMmZiMjQtOTQ1Yi00YTA4LWE3ZTQtYTZhNzRlZTIwMDFiIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.d5E6m_isNWy0Y5E-udUruMbThe3NHMb7x90rzOxlrEyyhZEqjuREP97KQXIospLY41TKj3VURJbRFebg-my4R8w1-OlaciDdoWND2juk8y_vIMlgYb9lLMnS1ZI5Ayq3OQ4Bh2TXLsZwQaBWoccyVSD1qCgZsCH-ZIbxJmefkM6k99fA8QWwNFL-bD1kHELBdZfk-26JSRWiA_0WocQZcC5DWsmbslwICo2yT59X4ancvxNA-mns0Wt41-sj9sAAr-qOAubGjpPC8-FqVZXeDTiuaAqQA2K3MRKMwHMZY6e-duwCltGll_kZf2jUlwfF7LLuT7YP6p7rxCjIhHaAMw"},
144 {"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJDNjVxMEVLUXlocGQxbTRmcjdTS08ySGVfbkF4Z0N0QWR3czY0ZDJCTHQ4In0.eyJleHAiOjE2MTU0MDcwMjYsImlhdCI6MTYxNTQwNjk2NiwianRpIjoiMzg1NjE4ODItOTA5MS00ODY3LTkzYmYtMmE3YmU4NTc3YmZiIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.Cmgz3aC_b_kpOmGM-_nRisgQul0d9Jg7BpMLe5F_fdryRhwhW5fQBZtz6FipQ0Tc4jggI6L3Dx1jS2kn823aWCR0x-OAFCawIXnwgAKuM1m2NL7Y6LKC07nytdB_qU4GknAl3jEG-tZIJBHQwYP-K6QKmAT9CdF1ZPbc9u8RgRCPN8UziYcOpvStiG829BO7cTzCt7tp5dJhem8_CnRWBKzelP1fs_z4fAQtW2sgyhX9SUYb5WON-4zrn4i01FlYUwZV-AC83zP6BuHIiy3XpAuTiTp2BjZ-1nzCLWBRpIm_lOObFeo-3AQqWPxzLVAmTFQMKReUF9T8ehL2Osr1XQ"},
145 {"eyJhbGciOiJSUzM4NCIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJnbm1BZnZtbHNpM2tLSDNWbE0xQUo4NVAyaGVrUThPTl9YdkpxczN4UEQ4In0.eyJleHAiOjE2MTU0MDcwNDUsImlhdCI6MTYxNTQwNjk4NSwianRpIjoiYzJiZGRhNGItMWNjNy00MzhmLWI1YzktMDk2ZDk4MTg4YWQ4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.F-y1IULtpWICLu0lrTniJwf3x1wHSQvVJ2BmXhRm-bhEdwftJG2Ep4rg4_SZPU8CZTazqSRQE4quWw5e8m8yyVrdpAts3NDAJB6m6Up1qQvN2YBtSoGjujzRZuJ72rOGqHf0e9wUQYWsmgE4Aes0kCeOlQ0EwfTnd6qfJaqYuZj9T0KIedt7T9KBmk3ndzDQALRJ2vo12b2M2DHL6gYqokUJ4lhw9Tnm785a6Bamc_F0otAKS5e4KVFhtRzCgdZWdEXX9VfwmtZpvZYImHWFe8HnB8jqLfRhKIc5xkXE0cwiuz6eYnneSRMrM3qAPus6fbc78rIVZl7Qaxa-h1vZYQ"},
146 {"eyJhbGciOiJSUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhcmxVeFg0aGg1NnJOTy1YZElQaERUN2JxQk1xY0J3TlF1UF9UblpKTkdzIn0.eyJleHAiOjE2MTU0MDcwNjcsImlhdCI6MTYxNTQwNzAwNywianRpIjoiYWNlNGQ5ODgtMjVjMS00NzkxLWJjZDgtNTQ3MzNiYTg0MTZiIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.BHygL0iGWEL46QdcnInqgjhgtlfBN8H2BMhFAK1sZuGB6rX-FGHFav0NgnWzT5Ae6wM3KqJY30aME5OOvycV--5w7ZX8uqnYjXYdLbJ-azLtP3Hw8vwY9u6GC81ZvWZdKvQNpbcuvtJYL2uhrbv0GdXcClTHmA-NiReGFuBFgo0fBX_ipjNx_q94OnaDxSHUSGeKqNFoNOttXBV7Xqa_K9j60zfoO9E2OV0jkYI5_8MPPZI85Y8XG7PUK2opg7LHNrFbB67C_RxJ7ZDKt0jBApzJyZ96_8UBSvNtBnytQO-CexOG-5y-nN3mcw7NU7g7dFxlb18Yur194h7VTT9tHQ"},
147 {"eyJhbGciOiJSUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhcmxVeFg0aGg1NnJOTy1YZElQaERUN2JxQk1xY0J3TlF1UF9UblpKTkdzIn0.eyJleHAiOjE2MTU0MDcwNjcsImlhdCI6MTYxNTQwNzAwNywianRpIjoiYWNlNGQ5ODgtMjVjMS00NzkxLWJjZDgtNTQ3MzNiYTg0MTZiIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.BHygL0iGWEL46QdcnInqgjhgtlfBN8H2BMhFAK1sZuGB6rX-FGHFav0NgnWzT5Ae6wM3KqJY30aME5OOvycV--5w7ZX8uqnYjXYdLbJ-azLtP3Hw8vwY9u6GC81ZvWZdKvQNpbcuvtJYL2uhrbv0GdXcClTHmA-NiReGFuBFgo0fBX_ipjNx_q94OnaDxSHUSGeKqNFoNOttXBV7Xqa_K9j60zfoO9E2OV0jkYI5_8MPPZI85Y8XG7PUK2opg7LHNrFbB67C_RxJ7ZDKt0jBApzJyZ96_8UBSvNtBnytQO-CexOG-5y-nN3mcw7NU7g7dFxlb18Yur194h7VTT9tHQ"},
148 {"eyJhbGciOiJFZERTQSIsImtpZCI6IlE1NkEiLCJrdHkiOiJPS1AiLCJ0eXAiOiJKV1QifQ.e30.BBUMb14EQqbhht6uR5V6_R7bQUiYtAi3v1bOvh4SO-_XA-WEs3k0OE2negGlsbIiXqcEP8pgHSB6r7JE0qUTCgiyJ_BCU7feuWyEohVW6ww7USRTMP4siphL3Xeewu0BKBg"},
149 {"eyJhbGciOiJIUzI1NiIsImtpZCI6ImhtYWMiLCJrdHkiOiJvY3QiLCJ0eXAiOiJKV1QifQ.e30.vZ8H2-9j1pDXLNL2GFKbZOkC2qyA0dr7AiTJpNjgLcY"},
150 }
151
152 if opts.RefreshInterval != 0 {
153 time.Sleep(opts.RefreshInterval)
154 }
155
156 for _, tc := range testCases {
157 t.Run(fmt.Sprintf("token: %s", tc.token), func(t *testing.T) {
158
159
160
161
162 _, err = jwt.Parse(tc.token, jwks.Keyfunc)
163 if err != nil {
164 if errors.Is(err, jwt.ErrInvalidKeyType) {
165 t.Fatalf(logFmt, "Invaild key type selected.", err)
166 }
167 }
168 })
169 }
170
171 jwks.EndBackground()
172 }
173 }
174
175
176 func TestJWKS_Use(t *testing.T) {
177 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
178 _, err := w.Write([]byte(jwksJSON))
179 if err != nil {
180 http.Error(w, err.Error(), http.StatusInternalServerError)
181 }
182 }))
183 defer server.Close()
184
185 jwksURL := server.URL
186 opts := keyfunc.Options{
187 JWKUseWhitelist: []keyfunc.JWKUse{keyfunc.UseOmitted, keyfunc.UseSignature},
188 }
189 jwks, err := keyfunc.Get(jwksURL, opts)
190 if err != nil {
191 t.Fatalf(logFmt, "Failed to get JWKS from testing URL.", err)
192 }
193
194 _, err = jwt.Parse(tokenUseEnc, jwks.Keyfunc)
195 if !errors.Is(err, keyfunc.ErrJWKUseWhitelist) {
196 t.Fatal(`Failed to return correct error for JWK with "use" parameter value of "enc".`)
197 }
198 }
199
200
201 func TestJWKS_UseNoWhitelistOverride(t *testing.T) {
202 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
203 _, err := w.Write([]byte(jwksJSON))
204 if err != nil {
205 http.Error(w, err.Error(), http.StatusInternalServerError)
206 }
207 }))
208 defer server.Close()
209
210 jwksURL := server.URL
211 opts := keyfunc.Options{
212 JWKUseWhitelist: []keyfunc.JWKUse{keyfunc.UseOmitted, keyfunc.UseSignature},
213 JWKUseNoWhitelist: true,
214 }
215 jwks, err := keyfunc.Get(jwksURL, opts)
216 if err != nil {
217 t.Fatalf(logFmt, "Failed to get JWKS from testing URL.", err)
218 }
219
220 _, err = jwt.Parse(tokenUseEnc, jwks.Keyfunc)
221 if err != nil {
222 t.Fatalf(logFmt, "The JWKUseNoWhitelist option should override the JWKUseWhitelist option.", err)
223 }
224 }
225
226
227 func TestJWKS_KIDs(t *testing.T) {
228 jwks, err := keyfunc.NewJSON([]byte(jwksJSON))
229 if err != nil {
230 t.Fatalf(logFmt, "Failed to create a JWKS from JSON.", err)
231 }
232
233 expectedKIDs := []string{
234 "zXew0UJ1h6Q4CCcd_9wxMzvcp5cEBifH0KWrCz2Kyxc",
235 "ebJxnm9B3QDBljB5XJWEu72qx6BawDaMAhwz4aKPkQ0",
236 "TVAAet63O3xy_KK6_bxVIu7Ra3_z1wlB543Fbwi5VaU",
237 "arlUxX4hh56rNO-XdIPhDT7bqBMqcBwNQuP_TnZJNGs",
238 "tW6ae7TomE6_2jooM-sf9N_6lWg7HNtaQXrDsElBzM4",
239 "Lx1FmayP2YBtxaqS1SKJRJGiXRKnw2ov5WmYIMG-BLE",
240 "gnmAfvmlsi3kKH3VlM1AJ85P2hekQ8ON_XvJqs3xPD8",
241 "CGt0ZWS4Lc5faiKSdi0tU0fjCAdvGROQRGU9iR7tV0A",
242 "C65q0EKQyhpd1m4fr7SKO2He_nAxgCtAdws64d2BLt8",
243 "Q56A",
244 "hmac",
245 "kidWithBadUse",
246 }
247
248 actual := jwks.KIDs()
249
250 actualLen := len(actual)
251 expectedLen := len(expectedKIDs)
252 if actualLen != expectedLen {
253 t.Fatalf("The number of key IDs was not as expected.\n Expected length: %d\n Actual length: %d\n Actual key IDs: %v", expectedLen, actualLen, actual)
254 }
255
256 for _, expectedKID := range expectedKIDs {
257 found := false
258 for _, kid := range actual {
259 if kid == expectedKID {
260 found = true
261 break
262 }
263 }
264 if !found {
265 t.Errorf("Failed to find expected key ID in the slice of key IDs in the JWKS.\n Missing: %s", expectedKID)
266 }
267 }
268 }
269
270
271 func TestJWKS_Len(t *testing.T) {
272 jwks, err := keyfunc.NewJSON([]byte(jwksJSON))
273 if err != nil {
274 t.Fatalf(logFmt, "Failed to create a JWKS from JSON.", err)
275 }
276
277 expectedKIDs := []string{
278 "zXew0UJ1h6Q4CCcd_9wxMzvcp5cEBifH0KWrCz2Kyxc",
279 "ebJxnm9B3QDBljB5XJWEu72qx6BawDaMAhwz4aKPkQ0",
280 "TVAAet63O3xy_KK6_bxVIu7Ra3_z1wlB543Fbwi5VaU",
281 "arlUxX4hh56rNO-XdIPhDT7bqBMqcBwNQuP_TnZJNGs",
282 "tW6ae7TomE6_2jooM-sf9N_6lWg7HNtaQXrDsElBzM4",
283 "Lx1FmayP2YBtxaqS1SKJRJGiXRKnw2ov5WmYIMG-BLE",
284 "gnmAfvmlsi3kKH3VlM1AJ85P2hekQ8ON_XvJqs3xPD8",
285 "CGt0ZWS4Lc5faiKSdi0tU0fjCAdvGROQRGU9iR7tV0A",
286 "C65q0EKQyhpd1m4fr7SKO2He_nAxgCtAdws64d2BLt8",
287 "Q56A",
288 "hmac",
289 "WW91IGdldCBhIGdvbGQgc3RhciDwn4yfCg",
290 }
291
292 actualLen := jwks.Len()
293 expectedLen := len(expectedKIDs)
294 if actualLen != expectedLen {
295 t.Fatalf("The number of key IDs was not as expected.\n Expected length: %d\n Actual length: %d\n", expectedLen, actualLen)
296 }
297 }
298
299
300 func TestRateLimit(t *testing.T) {
301 tempDir, err := os.MkdirTemp("", "*")
302 if err != nil {
303 t.Fatalf(logFmt, "Failed to create a temporary directory.", err)
304 }
305 defer func() {
306 err = os.RemoveAll(tempDir)
307 if err != nil {
308 t.Fatalf(logFmt, "Failed to remove temporary directory.", err)
309 }
310 }()
311
312 refreshes := uint(0)
313 refreshMux := sync.Mutex{}
314
315 server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
316 refreshMux.Lock()
317 refreshes++
318 refreshMux.Unlock()
319
320 writer.WriteHeader(200)
321 if _, serveErr := writer.Write([]byte(jwksJSON)); serveErr != nil {
322 t.Errorf(logFmt, "Failed to serve JWKS.", err)
323 }
324 }))
325 defer server.Close()
326
327 jwksURL := server.URL + jwksFilePath
328
329 refreshInterval := time.Second
330 refreshRateLimit := time.Millisecond * 500
331 refreshTimeout := time.Second
332 options := keyfunc.Options{
333 RefreshErrorHandler: func(err error) {
334 t.Errorf(logFmt, "The package itself had an error.", err)
335 },
336 RefreshInterval: refreshInterval,
337 RefreshRateLimit: refreshRateLimit,
338 RefreshTimeout: refreshTimeout,
339 RefreshUnknownKID: true,
340 }
341
342 jwks, err := keyfunc.Get(jwksURL, options)
343 if err != nil {
344 t.Fatalf(logFmt, "Failed to create *keyfunc.JWKS.", err)
345 }
346 defer jwks.EndBackground()
347
348
349
350
351
352
353
354
355 token1 := "eyJraWQiOiI0NWU3ZDcyMiIsInR5cCI6IkpXVCIsImFsZyI6IlJTNTEyIn0.eyJzdWIiOiJBbmRyZWEiLCJhdWQiOiJUYXNodWFuIiwiaXNzIjoiandrcy1zZXJ2aWNlLmFwcHNwb3QuY29tIiwiZXhwIjoxNjI0NzU2OTAwLCJpYXQiOjE2MjQ3NTY4OTUsImp0aSI6IjA5ZjkzZjljLTU0ZjMtNDM5Yi04Njg2LWZhMGYwMjlmYmIwZSJ9.g643vWnvDvR5u5TeCUaCblp-Ss8SPWoZrOxBo3y6WP9xQnRW63VSbacCirl-5nGRPoX6vostZAkRyUl62ICQHpTj3bRnDY4ZbkcQ42xtrWMBsI2Sw6dAmZtGsCR_tguQZmvdKE4gVNnFWLp0hBjCeLxPVbc59vC6njMdz7XHcOdW7RXN6iUYjLFoPAr4Qg93Vbrwfo9Qmkm8bDgbnuoJ3aQq0RFa02G1KC2-cx8SuUbxso_Uu7ddY6HDRL5OPF3xS9cKO5ty4zCfGYIVDhfH7V-zA2cJZyA2dlv3Ddd-ntU42aud0M4PcTTdjHf1CE29sCZHk5wTRgxsTjfWglYQQiVQJEkw6DD6kTlQ_MwN4p_OWNj06b55mXM6Bj9c9y8TfPLETDy_PRc1lHu1PuiizLg019JaGidpTLF8IdKTa9emkEnf2n8xWi-YMkkRk57hpuc56GmnBR0d8ODfuL0XILlQp2guFsVRo9A4Sdqy7fGdZGoSS4XzSR-TIEw7W_KSqlYCtWC0xNk1Kze3xSY2mDqrn1YFFlvXgXQlgzU8GN1eL7QRRQlxaPGti2wEH6OYH4A160nR_OM-zFBobpQn79g8HsK8yZgPiY0p94F6pvKBQtSHDBvAe3W0-UHYfspwT9cQGVgqCGol6A8XNeBlVQpko9ves4UgCRSb6o9u_p4"
356 token2 := "eyJraWQiOiIyYTFkODRhMCIsInR5cCI6IkpXVCIsImFsZyI6IkVTMzg0In0.eyJzdWIiOiJBbmRyZWEiLCJhdWQiOiJUYXNodWFuIiwiaXNzIjoiandrcy1zZXJ2aWNlLmFwcHNwb3QuY29tIiwiZXhwIjoxNjI0NzU3MjExLCJpYXQiOjE2MjQ3NTcyMDYsImp0aSI6ImU4YjQ1YmIwLTczZjgtNDkzNi04MjQxLWE1OGFlZWMyZWE2NCJ9.6Isd4unU2TAmRB1SouaHBV9LUjFGIuhOrxkQlDjh6qKRgb7UsiPtQm87S2qrriLaFjyCmrmU6cDpVBpTOutjPxweIqT-1EfsS-dkENIVWPVgQ5-KuNu2jXyGYpPeFBUA"
357 token3 := "eyJraWQiOiIxZjEyOGFkZSIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJSZWJlY2NhIiwiYXVkIjoiQWxpY2UiLCJpc3MiOiJqd2tzLXNlcnZpY2UuYXBwc3BvdC5jb20iLCJleHAiOjE2MjQ3NTkzODIsImlhdCI6MTYyNDc1OTM3NywianRpIjoiMzU2MWY4MDctNDRkNi00OWE5LWFlYWItMmQ1MjQ2YWYxNDhlIn0.5eZbJlvnaFsRwPhBHmXljp9vgsrB0Q9d3dSz4va29ahTKsFGFo8tYy0e69ehqSb-dbFy9azRRtygwwtYuaEFuA"
358 token4 := "eyJraWQiOiIyZDQ3NjUwYSIsInR5cCI6IkpXVCIsImFsZyI6IlBTMzg0In0.eyJzdWIiOiJGcmVkYSIsImF1ZCI6Ikx1Y2lhIiwiaXNzIjoiandrcy1zZXJ2aWNlLmFwcHNwb3QuY29tIiwiZXhwIjoxNjI0ODA0MTk0LCJpYXQiOjE2MjQ4MDQxODksImp0aSI6IjdjNTQ2Y2RmLTYwMTEtNDI3Ny04Y2Q0LTMwNjZmZTYwNTExZSJ9.hQm-OP_MMk8_S13-ohiINRuDP2IlCiB3yn8Ov6qTjeFbq4gZ6MegeJH_qiZOvXqlzOAwpwd5P4nm5JeS6LlNGdW6V_agwYwnAd08GI7APQNRib692_sEk1DKdSk-S-Y8V_ZAgeTT8asdaSDw4EBPxkDvROcuEqesZrfqnrOcpdqqa2BcmwX8q5sLtQ8TMp4cOvEZg-J8_0j2kdCUkv_n9ZdsRoA3EUT8M1bYqnGRRxIRqflsm-S_xq3HxMAnPF5hPlqIKFVKuRsU0SKgcHZGwXpuK2lJqPobl6MI987tGrc9sPPFzVkNYxeltcxu34-ZjzN6iCQN8r0w-mfqCZav7A"
359
360
361 waitGroup := sync.WaitGroup{}
362 waitGroup.Add(3)
363 go func() {
364 defer waitGroup.Done()
365 if _, parseErr := jwt.Parse(token1, jwks.Keyfunc); parseErr != nil {
366 if errors.Is(parseErr, jwt.ErrInvalidKeyType) {
367 t.Errorf(logFmt, "Invaild key type selected.", parseErr)
368 }
369 }
370 }()
371 go func() {
372 defer waitGroup.Done()
373 if _, parseErr := jwt.Parse(token2, jwks.Keyfunc); parseErr != nil {
374 if errors.Is(parseErr, jwt.ErrInvalidKeyType) {
375 t.Errorf(logFmt, "Invaild key type selected.", parseErr)
376 }
377 }
378 }()
379 go func() {
380 defer waitGroup.Done()
381 if _, parseErr := jwt.Parse(token3, jwks.Keyfunc); parseErr != nil {
382 if errors.Is(parseErr, jwt.ErrInvalidKeyType) {
383 t.Errorf(logFmt, "Invaild key type selected.", parseErr)
384 }
385 }
386 }()
387 if _, parseErr := jwt.Parse(token4, jwks.Keyfunc); parseErr != nil {
388 if errors.Is(parseErr, jwt.ErrInvalidKeyType) {
389 t.Fatalf(logFmt, "Invaild key type selected.", parseErr)
390 }
391 }
392 waitGroup.Wait()
393
394
395 refreshMux.Lock()
396 expected := uint(2)
397 if refreshes != expected {
398 t.Fatalf("An incorrect number of refreshes occurred.\n Expected: %d\n Got: %d\n", expected, refreshes)
399 }
400 refreshMux.Unlock()
401
402
403 time.Sleep(refreshRateLimit + time.Millisecond*100)
404 refreshMux.Lock()
405 expected = uint(3)
406 if refreshes != expected {
407 t.Fatalf("An incorrect number of refreshes occurred.\n Expected: %d\n Got: %d\n", expected, refreshes)
408 }
409 refreshMux.Unlock()
410
411
412 time.Sleep(refreshInterval + time.Millisecond*100)
413 refreshMux.Lock()
414 expected = uint(4)
415 if refreshes != expected {
416 t.Fatalf("An incorrect number of refreshes occurred.\n Expected: %d\n Got: %d\n", expected, refreshes)
417 }
418 refreshMux.Unlock()
419 }
420
421
422 func TestRawJWKS(t *testing.T) {
423 tempDir, err := os.MkdirTemp("", "*")
424 if err != nil {
425 t.Fatalf(logFmt, "Failed to create a temporary directory.", err)
426 }
427 defer func() {
428 err = os.RemoveAll(tempDir)
429 if err != nil {
430 t.Fatalf(logFmt, "Failed to remove temporary directory.", err)
431 }
432 }()
433
434 jwksFile := filepath.Join(tempDir, jwksFilePath)
435
436 err = os.WriteFile(jwksFile, []byte(jwksJSON), 0600)
437 if err != nil {
438 t.Fatalf(logFmt, "Failed to write JWKS file to temporary directory.", err)
439 }
440
441 server := httptest.NewServer(http.FileServer(http.Dir(tempDir)))
442 defer server.Close()
443
444 jwksURL := server.URL + jwksFilePath
445
446 jwks, err := keyfunc.Get(jwksURL, keyfunc.Options{})
447 if err != nil {
448 t.Fatalf(logFmt, "Failed to get JWKS from testing URL.", err)
449 }
450
451 raw := jwks.RawJWKS()
452 if !bytes.Equal(raw, []byte(jwksJSON)) {
453 t.Fatalf("Raw JWKS does not match remote JWKS resource.")
454 }
455
456
457 emptySlice := make([]byte, len(raw))
458 copy(raw, emptySlice)
459
460 nextRaw := jwks.RawJWKS()
461 if bytes.Equal(nextRaw, emptySlice) {
462 t.Fatalf("Raw JWKS is not a copy.")
463 }
464 }
465
466
467 func TestRequestFactory(t *testing.T) {
468 var fullJWKSHandler http.Handler
469 {
470 tempDir, err := os.MkdirTemp("", "*")
471 if err != nil {
472 t.Fatalf(logFmt, "Failed to create a temporary directory.", err)
473 }
474 defer func() {
475 err = os.RemoveAll(tempDir)
476 if err != nil {
477 t.Fatalf(logFmt, "Failed to remove temporary directory.", err)
478 }
479 }()
480
481 jwksFile := filepath.Join(tempDir, jwksFilePath)
482
483 err = os.WriteFile(jwksFile, []byte(jwksJSON), 0600)
484 if err != nil {
485 t.Fatalf(logFmt, "Failed to write JWKS file to temporary directory.", err)
486 }
487
488 fullJWKSHandler = http.FileServer(http.Dir(tempDir))
489 }
490 var emptyJWKSHandler http.Handler
491 {
492 tempDir, err := os.MkdirTemp("", "*")
493 if err != nil {
494 t.Fatalf(logFmt, "Failed to create a temporary directory.", err)
495 }
496 defer func() {
497 err = os.RemoveAll(tempDir)
498 if err != nil {
499 t.Fatalf(logFmt, "Failed to remove temporary directory.", err)
500 }
501 }()
502
503 jwksFile := filepath.Join(tempDir, jwksFilePath)
504
505 err = os.WriteFile(jwksFile, []byte(emptyJWKSJSON), 0600)
506 if err != nil {
507 t.Fatalf(logFmt, "Failed to write JWKS file to temporary directory.", err)
508 }
509
510 emptyJWKSHandler = http.FileServer(http.Dir(tempDir))
511 }
512
513 const (
514 fullJWKSUserAgent = "full-jwks-please"
515 userAgentHeader = "User-Agent"
516 )
517 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
518 switch r.Header.Get(userAgentHeader) {
519 case fullJWKSUserAgent:
520 fullJWKSHandler.ServeHTTP(w, r)
521 default:
522 emptyJWKSHandler.ServeHTTP(w, r)
523 }
524 }))
525 defer server.Close()
526
527 jwksURL := server.URL + jwksFilePath
528
529 optsFail := keyfunc.Options{
530 RequestFactory: func(ctx context.Context, url string) (*http.Request, error) {
531 badURL := fmt.Sprintf("%s/does/not/exist", url)
532 return http.NewRequestWithContext(ctx, http.MethodGet, badURL, bytes.NewReader(nil))
533 },
534 }
535
536 _, err := keyfunc.Get(jwksURL, optsFail)
537 if err == nil {
538 t.Fatalf("Creation of *keyfunc.JWKS reading from bad URL must fail.")
539 }
540
541 optsSuccess := keyfunc.Options{
542 RequestFactory: func(ctx context.Context, url string) (*http.Request, error) {
543 return http.NewRequestWithContext(ctx, http.MethodGet, url, bytes.NewReader(nil))
544 },
545 }
546
547 jwks, err := keyfunc.Get(jwksURL, optsSuccess)
548 if err != nil {
549 t.Fatalf(logFmt, "Failed to get JWKS from testing URL.", err)
550 }
551
552 if len(jwks.ReadOnlyKeys()) != 0 {
553 t.Fatalf("JWKS should be empty due to lack of custom HTTP header.")
554 }
555
556 optsCustomHeader := keyfunc.Options{
557 RequestFactory: func(ctx context.Context, url string) (*http.Request, error) {
558 req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, bytes.NewReader(nil))
559 if err != nil {
560 return nil, fmt.Errorf("failed to create request: %w", err)
561 }
562 req.Header.Set(userAgentHeader, fullJWKSUserAgent)
563 return req, nil
564 },
565 }
566
567 jwks, err = keyfunc.Get(jwksURL, optsCustomHeader)
568 if err != nil {
569 t.Fatalf(logFmt, "Failed to get JWKS from testing URL.", err)
570 }
571
572 if len(jwks.ReadOnlyKeys()) == 0 {
573 t.Fatalf("JWKS should not be empty due to custom HTTP header.")
574 }
575 }
576
577
578 func TestUnknownKIDRefresh(t *testing.T) {
579 tempDir, err := os.MkdirTemp("", "*")
580 if err != nil {
581 t.Fatalf(logFmt, "Failed to create a temporary directory.", err)
582 }
583 defer func() {
584 err = os.RemoveAll(tempDir)
585 if err != nil {
586 t.Fatalf(logFmt, "Failed to remove temporary directory.", err)
587 }
588 }()
589
590 jwksFile := filepath.Join(tempDir, strings.TrimPrefix(jwksFilePath, "/"))
591
592 err = os.WriteFile(jwksFile, []byte(emptyJWKSJSON), 0600)
593 if err != nil {
594 t.Fatalf(logFmt, "Failed to write JWKS file to temporary directory.", err)
595 }
596
597 server := httptest.NewServer(http.FileServer(http.Dir(tempDir)))
598 defer server.Close()
599
600 testingRefreshErrorHandler := func(err error) {
601 t.Fatalf(logFmt, "Unhandled JWKS error.", err)
602 }
603
604 jwksURL := server.URL + jwksFilePath
605
606 options := keyfunc.Options{
607 RefreshErrorHandler: testingRefreshErrorHandler,
608 RefreshUnknownKID: true,
609 }
610
611 jwks, err := keyfunc.Get(jwksURL, options)
612 if err != nil {
613 t.Fatalf(logFmt, "Failed to create *keyfunc.JWKS.", err)
614 }
615 defer jwks.EndBackground()
616
617 err = os.WriteFile(jwksFile, []byte(jwksJSON), 0600)
618 if err != nil {
619 t.Fatalf(logFmt, "Failed to write JWKS file to temporary directory.", err)
620 }
621
622
623 token := "eyJhbGciOiJFUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJDR3QwWldTNExjNWZhaUtTZGkwdFUwZmpDQWR2R1JPUVJHVTlpUjd0VjBBIn0.eyJleHAiOjE2MTU0MDY4NjEsImlhdCI6MTYxNTQwNjgwMSwianRpIjoiYWVmOWQ5YjItN2EyYy00ZmQ4LTk4MzktODRiMzQ0Y2VmYzZhIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJhZDEyOGRmMS0xMTQwLTRlNGMtYjA5Ny1hY2RjZTcwNWJkOWIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ0b2tlbmRlbG1lIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SG9zdCI6IjE3Mi4yMC4wLjEiLCJjbGllbnRJZCI6InRva2VuZGVsbWUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6InNlcnZpY2UtYWNjb3VudC10b2tlbmRlbG1lIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4yMC4wLjEifQ.iQ77QGoPDNjR2oWLu3zT851mswP8J-h_nrGhs3fpa_tFB3FT1deKPGkjef9JOTYFI-CIVxdCFtW3KODOaw9Nrw"
624
625
626
627
628
629 _, err = jwt.Parse(token, jwks.Keyfunc)
630 if err != nil {
631 if errors.Is(err, jwt.ErrInvalidKeyType) {
632 t.Fatalf(logFmt, "Invaild key type selected.", err)
633 }
634 }
635 }
636
637
638 func TestReadOnlyKeys(t *testing.T) {
639 jwks, err := keyfunc.NewJSON([]byte(jwksJSON))
640 if err != nil {
641 t.Fatalf(logFmt, "Failed to create a JWKS from JSON.", err)
642 }
643
644 for _, key := range jwks.ReadOnlyKeys() {
645 switch key.(type) {
646 case *rsa.PublicKey:
647
648 case *ecdsa.PublicKey:
649
650 case ed25519.PublicKey:
651
652 case []byte:
653
654 default:
655 t.Errorf("Invalid type %T in .ReadOnlyKeys() method.", key)
656 }
657 }
658 }
659
View as plain text