Skip to content

Commit de67265

Browse files
author
Thibaut Cholley
committed
Change for PR
1 parent 2a121c1 commit de67265

File tree

3 files changed

+46
-52
lines changed

3 files changed

+46
-52
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module github.com/Cafeine42/caddy-jwt
1+
module github.com/ggicci/caddy-jwt
22

33
go 1.20
44

jwt.go

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@ func init() {
3030
type User = caddyauth.User
3131
type Token = jwt.Token
3232

33+
// jwkCacheEntry stores the JWK cache information for a specific URL
34+
type jwkCacheEntry struct {
35+
URL string
36+
Cache *jwk.Cache
37+
CachedSet jwk.Set
38+
}
39+
40+
// refresh refreshes the JWK cache for this entry
41+
func (entry *jwkCacheEntry) refresh(ctx context.Context, logger *zap.Logger) error {
42+
_, err := entry.Cache.Refresh(ctx, entry.URL)
43+
if err != nil {
44+
logger.Warn("failed to refresh JWK cache", zap.Error(err), zap.String("url", entry.URL))
45+
return err
46+
}
47+
return nil
48+
}
49+
3350
// JWTAuth facilitates JWT (JSON Web Token) authentication.
3451
type JWTAuth struct {
3552
// SignKey is the key used by the signing algorithm to verify the signature.
@@ -151,10 +168,7 @@ type JWTAuth struct {
151168
parsedSignKey interface{} // can be []byte, *rsa.PublicKey, *ecdsa.PublicKey, etc.
152169

153170
// JWK cache by resolved URL to support placeholders in JWKURL
154-
jwkCaches map[string]*struct {
155-
cache *jwk.Cache
156-
cachedSet jwk.Set
157-
}
171+
jwkCaches map[string]*jwkCacheEntry
158172
}
159173

160174
// CaddyModule implements caddy.Module interface.
@@ -182,19 +196,13 @@ func (ja *JWTAuth) usingJWK() bool {
182196
}
183197

184198
func (ja *JWTAuth) setupJWKLoader() {
185-
// Initialiser le cache pour toutes les URL possibles
186-
ja.jwkCaches = make(map[string]*struct {
187-
cache *jwk.Cache
188-
cachedSet jwk.Set
189-
})
190-
ja.logger.Info("JWK cache initialized for placeholder URL", zap.String("placeholder_url", ja.JWKURL))
199+
// Initialize cache for all possible URLs
200+
ja.jwkCaches = make(map[string]*jwkCacheEntry)
201+
ja.logger.Info("JWK cache initialized for JWK URL", zap.String("jwk_url", ja.JWKURL))
191202
}
192203

193204
// getOrCreateJWKCache retrieves or creates a cache for a specific JWK URL
194-
func (ja *JWTAuth) getOrCreateJWKCache(resolvedURL string) (*struct {
195-
cache *jwk.Cache
196-
cachedSet jwk.Set
197-
}, error) {
205+
func (ja *JWTAuth) getOrCreateJWKCache(resolvedURL string) (*jwkCacheEntry, error) {
198206
// If the URL is empty, return an error
199207
if resolvedURL == "" {
200208
return nil, fmt.Errorf("resolved JWK URL is empty")
@@ -212,44 +220,27 @@ func (ja *JWTAuth) getOrCreateJWKCache(resolvedURL string) (*struct {
212220
return nil, fmt.Errorf("failed to register JWK URL: %w", err)
213221
}
214222

223+
// Create cache entry before attempting refresh
224+
entry := &jwkCacheEntry{
225+
URL: resolvedURL,
226+
Cache: cache,
227+
CachedSet: jwk.NewCachedSet(cache, resolvedURL),
228+
}
229+
215230
// Try to refresh the cache immediately
216-
_, err = cache.Refresh(context.Background(), resolvedURL)
231+
err = entry.refresh(context.Background(), ja.logger)
217232
if err != nil {
218233
ja.logger.Warn("failed to refresh JWK cache during initialization", zap.Error(err), zap.String("url", resolvedURL))
219234
// Continue even in case of error, the important thing is that the URL is registered
220235
}
221236

222-
cachedSet := jwk.NewCachedSet(cache, resolvedURL)
223-
entry := &struct {
224-
cache *jwk.Cache
225-
cachedSet jwk.Set
226-
}{
227-
cache: cache,
228-
cachedSet: cachedSet,
229-
}
230-
231237
// Register the entry in the cache
232238
ja.jwkCaches[resolvedURL] = entry
233-
ja.logger.Info("new JWK cache created", zap.String("url", resolvedURL), zap.Int("loaded_keys", cachedSet.Len()))
239+
ja.logger.Info("new JWK cache created", zap.String("url", resolvedURL), zap.Int("loaded_keys", entry.CachedSet.Len()))
234240

235241
return entry, nil
236242
}
237243

238-
// refreshJWKCache refreshes the JWK cache for a specific URL. It validates the JWKs from the given URL.
239-
func (ja *JWTAuth) refreshJWKCache(resolvedURL string) error {
240-
entry, err := ja.getOrCreateJWKCache(resolvedURL)
241-
if err != nil {
242-
return err
243-
}
244-
245-
_, err = entry.cache.Refresh(context.Background(), resolvedURL)
246-
if err != nil {
247-
ja.logger.Warn("failed to refresh JWK cache", zap.Error(err), zap.String("url", resolvedURL))
248-
return err
249-
}
250-
return nil
251-
}
252-
253244
// Validate implements caddy.Validator interface.
254245
func (ja *JWTAuth) Validate() error {
255246
if !ja.SkipVerification {
@@ -300,15 +291,18 @@ func (ja *JWTAuth) validateSignatureKeys() error {
300291
return nil
301292
}
302293

294+
// resolveJWKURL prend une requête HTTP et résout l'URL JWK avec des espaces réservés
295+
func (ja *JWTAuth) resolveJWKURL(request *http.Request) string {
296+
replacer := request.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
297+
return replacer.ReplaceAll(ja.JWKURL, "")
298+
}
299+
303300
func (ja *JWTAuth) keyProvider(request *http.Request) jws.KeyProviderFunc {
304-
return func(context context.Context, sink jws.KeySink, sig *jws.Signature, _ *jws.Message) error {
301+
return func(curContext context.Context, sink jws.KeySink, sig *jws.Signature, _ *jws.Message) error {
305302
if ja.usingJWK() {
306-
// Resolve JWKURL with placeholders
307-
replacer := request.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
308-
resolvedURL := replacer.ReplaceAll(ja.JWKURL, "")
303+
resolvedURL := ja.resolveJWKURL(request)
309304

310-
ja.logger.Info("JWK unresolved", zap.String("placeholder_url", ja.JWKURL))
311-
ja.logger.Info("JWK resolved", zap.String("placeholder_url", resolvedURL))
305+
ja.logger.Info("JWK URL", zap.String("unresolved", ja.JWKURL), zap.String("resolved", resolvedURL))
312306

313307
// Get or create the cache for this URL
314308
cacheEntry, err := ja.getOrCreateJWKCache(resolvedURL)
@@ -318,10 +312,10 @@ func (ja *JWTAuth) keyProvider(request *http.Request) jws.KeyProviderFunc {
318312

319313
// Use the key set associated with this URL
320314
kid := sig.ProtectedHeaders().KeyID()
321-
key, found := cacheEntry.cachedSet.LookupKeyID(kid)
315+
key, found := cacheEntry.CachedSet.LookupKeyID(kid)
322316
if !found {
323317
// Trigger an asynchronous refresh if the key is not found
324-
go ja.refreshJWKCache(resolvedURL)
318+
go cacheEntry.refresh(context.Background(), ja.logger)
325319

326320
if kid == "" {
327321
return fmt.Errorf("missing kid in JWT header")

jwt_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ func TestJWK(t *testing.T) {
806806
cachedEntry, exists := ja.jwkCaches[TestJWKURL]
807807
assert.True(t, exists, "Le cache devrait exister pour l'URL de test")
808808
assert.NotNil(t, cachedEntry)
809-
assert.Equal(t, 1, cachedEntry.cachedSet.Len())
809+
assert.Equal(t, 1, cachedEntry.CachedSet.Len())
810810
}
811811

812812
func TestJWKSet(t *testing.T) {
@@ -834,7 +834,7 @@ func TestJWKSet(t *testing.T) {
834834
cachedEntry, exists := ja.jwkCaches[TestJWKSetURL]
835835
assert.True(t, exists, "Le cache devrait exister pour l'URL du set JWK")
836836
assert.NotNil(t, cachedEntry)
837-
assert.Equal(t, 2, cachedEntry.cachedSet.Len())
837+
assert.Equal(t, 2, cachedEntry.CachedSet.Len())
838838
}
839839

840840
func TestJWKSet_KeyNotFound(t *testing.T) {
@@ -859,7 +859,7 @@ func TestJWKSet_KeyNotFound(t *testing.T) {
859859
cachedEntry, exists := ja.jwkCaches[TestJWKSetURLInapplicable]
860860
assert.True(t, exists, "Le cache devrait exister pour l'URL inapplicable")
861861
assert.NotNil(t, cachedEntry)
862-
assert.Equal(t, 2, cachedEntry.cachedSet.Len())
862+
assert.Equal(t, 2, cachedEntry.CachedSet.Len())
863863

864864
// Vérifier que l'authentification a échoué car la clé n'est pas trouvée
865865
assert.Error(t, err)

0 commit comments

Comments
 (0)