Skip to content

Commit 0f63cd9

Browse files
authored
Refactor jwt verifier (#1062)
1 parent 76af670 commit 0f63cd9

File tree

1 file changed

+57
-69
lines changed

1 file changed

+57
-69
lines changed

internal/jwtverify/token_verifier_jwt.go

Lines changed: 57 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/centrifugal/centrifugo/v6/internal/config"
1717
"github.com/centrifugal/centrifugo/v6/internal/jwks"
1818
"github.com/centrifugal/centrifugo/v6/internal/subsource"
19+
"github.com/centrifugal/centrifugo/v6/internal/tools"
1920

2021
"github.com/centrifugal/centrifuge"
2122
"github.com/cristalhq/jwt/v5"
@@ -102,18 +103,20 @@ func NewTokenVerifierJWT(config VerifierConfig, cfgContainer *config.Container)
102103
userIDClaim: config.UserIDClaim,
103104
}
104105

105-
algorithms, err := newAlgorithms(config.HMACSecretKey, config.RSAPublicKey, config.ECDSAPublicKey)
106-
if err != nil {
107-
return nil, fmt.Errorf("error initializing token algorithms: %w", err)
108-
}
109-
verifier.algorithms = algorithms
110-
111106
if config.JWKSPublicEndpoint != "" {
112107
mng, err := jwks.NewManager(config.JWKSPublicEndpoint)
113108
if err != nil {
114109
return nil, fmt.Errorf("error creating JWK manager: %w", err)
115110
}
116111
verifier.jwksManager = &jwksManager{mng}
112+
log.Info().Str("endpoint", strings.Join(tools.RedactedLogURLs(config.JWKSPublicEndpoint), ",")).
113+
Msg("JWKS manager created")
114+
} else {
115+
alg, err := newAlgorithms(config.HMACSecretKey, config.RSAPublicKey, config.ECDSAPublicKey)
116+
if err != nil {
117+
return nil, fmt.Errorf("error initializing token algorithms: %w", err)
118+
}
119+
verifier.algorithms = alg
117120
}
118121

119122
return verifier, nil
@@ -425,31 +428,19 @@ func (verifier *VerifierJWT) verifySignatureByJWK(token *jwt.Token, tokenVars ma
425428
return verifier.jwksManager.verify(token, tokenVars)
426429
}
427430

428-
func (verifier *VerifierJWT) VerifyConnectToken(t string, skipVerify bool) (ConnectToken, error) {
429-
token, err := jwt.ParseNoVerify([]byte(t)) // Will be verified later.
430-
if err != nil {
431-
return ConnectToken{}, fmt.Errorf("%w: %v", ErrInvalidToken, err)
432-
}
433-
434-
claims, err := claimsDecoder.DecodeConnectClaims(token.Claims())
435-
if err != nil {
436-
return ConnectToken{}, fmt.Errorf("%w: %v", ErrInvalidToken, err)
437-
}
438-
431+
func (verifier *VerifierJWT) validateClaims(claims jwt.RegisteredClaims, tokenVars map[string]any) error {
439432
if verifier.audience != "" && !claims.IsForAudience(verifier.audience) {
440-
return ConnectToken{}, fmt.Errorf("%w: invalid audience", ErrInvalidToken)
433+
return fmt.Errorf("%w: invalid audience", ErrInvalidToken)
441434
}
442435

443436
if verifier.issuer != "" && !claims.IsIssuer(verifier.issuer) {
444-
return ConnectToken{}, fmt.Errorf("%w: invalid issuer", ErrInvalidToken)
437+
return fmt.Errorf("%w: invalid issuer", ErrInvalidToken)
445438
}
446439

447-
tokenVars := map[string]any{}
448-
449440
if verifier.issuerRe != nil {
450441
match := verifier.issuerRe.FindStringSubmatch(claims.Issuer)
451442
if len(match) == 0 {
452-
return ConnectToken{}, fmt.Errorf("%w: issuer not matched", ErrInvalidToken)
443+
return fmt.Errorf("%w: issuer not matched", ErrInvalidToken)
453444
}
454445
for i, name := range verifier.issuerRe.SubexpNames() {
455446
if i != 0 && name != "" {
@@ -460,8 +451,8 @@ func (verifier *VerifierJWT) VerifyConnectToken(t string, skipVerify bool) (Conn
460451

461452
if verifier.audienceRe != nil {
462453
matched := false
463-
for _, audience := range claims.Audience {
464-
match := verifier.audienceRe.FindStringSubmatch(audience)
454+
for _, aud := range claims.Audience {
455+
match := verifier.audienceRe.FindStringSubmatch(aud)
465456
if len(match) == 0 {
466457
continue
467458
}
@@ -474,10 +465,30 @@ func (verifier *VerifierJWT) VerifyConnectToken(t string, skipVerify bool) (Conn
474465
break
475466
}
476467
if !matched {
477-
return ConnectToken{}, fmt.Errorf("%w: audience not matched", ErrInvalidToken)
468+
return fmt.Errorf("%w: audience not matched", ErrInvalidToken)
478469
}
479470
}
480471

472+
return nil
473+
}
474+
475+
func (verifier *VerifierJWT) VerifyConnectToken(t string, skipVerify bool) (ConnectToken, error) {
476+
token, err := jwt.ParseNoVerify([]byte(t)) // Will be verified later.
477+
if err != nil {
478+
return ConnectToken{}, fmt.Errorf("%w: %v", ErrInvalidToken, err)
479+
}
480+
481+
claims, err := claimsDecoder.DecodeConnectClaims(token.Claims())
482+
if err != nil {
483+
return ConnectToken{}, fmt.Errorf("%w: %v", ErrInvalidToken, err)
484+
}
485+
486+
tokenVars := map[string]any{}
487+
488+
if err := verifier.validateClaims(claims.RegisteredClaims, tokenVars); err != nil {
489+
return ConnectToken{}, err
490+
}
491+
481492
if !skipVerify {
482493
if verifier.jwksManager != nil {
483494
err = verifier.verifySignatureByJWK(token, tokenVars)
@@ -638,46 +649,10 @@ func (verifier *VerifierJWT) VerifySubscribeToken(t string, skipVerify bool) (Su
638649
return SubscribeToken{}, fmt.Errorf("%w: %v", ErrInvalidToken, err)
639650
}
640651

641-
if verifier.audience != "" && !claims.IsForAudience(verifier.audience) {
642-
return SubscribeToken{}, fmt.Errorf("%w: invalid audience", ErrInvalidToken)
643-
}
644-
645-
if verifier.issuer != "" && !claims.IsIssuer(verifier.issuer) {
646-
return SubscribeToken{}, fmt.Errorf("%w: invalid issuer", ErrInvalidToken)
647-
}
648-
649652
tokenVars := map[string]any{}
650653

651-
if verifier.issuerRe != nil {
652-
match := verifier.issuerRe.FindStringSubmatch(claims.Issuer)
653-
if len(match) == 0 {
654-
return SubscribeToken{}, fmt.Errorf("%w: issuer not matched", ErrInvalidToken)
655-
}
656-
for i, name := range verifier.issuerRe.SubexpNames() {
657-
if i != 0 && name != "" {
658-
tokenVars[name] = match[i]
659-
}
660-
}
661-
}
662-
663-
if verifier.audienceRe != nil {
664-
matched := false
665-
for _, audience := range claims.Audience {
666-
match := verifier.audienceRe.FindStringSubmatch(audience)
667-
if len(match) == 0 {
668-
continue
669-
}
670-
matched = true
671-
for i, name := range verifier.audienceRe.SubexpNames() {
672-
if i != 0 && name != "" {
673-
tokenVars[name] = match[i]
674-
}
675-
}
676-
break
677-
}
678-
if !matched {
679-
return SubscribeToken{}, fmt.Errorf("%w: audience not matched", ErrInvalidToken)
680-
}
654+
if err := verifier.validateClaims(claims.RegisteredClaims, tokenVars); err != nil {
655+
return SubscribeToken{}, err
681656
}
682657

683658
if !skipVerify {
@@ -795,26 +770,39 @@ func (verifier *VerifierJWT) Reload(config VerifierConfig) error {
795770
verifier.mu.Lock()
796771
defer verifier.mu.Unlock()
797772

798-
alg, err := newAlgorithms(config.HMACSecretKey, config.RSAPublicKey, config.ECDSAPublicKey)
799-
if err != nil {
800-
return err
801-
}
802-
803773
var audienceRe *regexp.Regexp
804774
var issuerRe *regexp.Regexp
805775
if config.AudienceRegex != "" {
776+
var err error
806777
audienceRe, err = regexp.Compile(config.AudienceRegex)
807778
if err != nil {
808779
return fmt.Errorf("error compiling audience regex: %w", err)
809780
}
810781
}
811782
if config.IssuerRegex != "" {
783+
var err error
812784
issuerRe, err = regexp.Compile(config.IssuerRegex)
813785
if err != nil {
814786
return fmt.Errorf("error compiling issuer regex: %w", err)
815787
}
816788
}
817-
verifier.algorithms = alg
789+
790+
if config.JWKSPublicEndpoint != "" {
791+
mng, err := jwks.NewManager(config.JWKSPublicEndpoint)
792+
if err != nil {
793+
return fmt.Errorf("error creating JWK manager: %w", err)
794+
}
795+
verifier.jwksManager = &jwksManager{mng}
796+
verifier.algorithms = nil
797+
} else {
798+
alg, err := newAlgorithms(config.HMACSecretKey, config.RSAPublicKey, config.ECDSAPublicKey)
799+
if err != nil {
800+
return err
801+
}
802+
verifier.algorithms = alg
803+
verifier.jwksManager = nil
804+
}
805+
818806
verifier.audience = config.Audience
819807
verifier.audienceRe = audienceRe
820808
verifier.issuer = config.Issuer

0 commit comments

Comments
 (0)