Files
upstream-centrifugo/internal/jwtverify/token_verifier_jwt_race_test.go
upstream-mirror b352a9a30d
Some checks failed
test / Lint (push) Failing after 3s
test / Test with Go 1.26.8 (push) Failing after 2s
snapshot of https://github.com/centrifugal/centrifugo.git (master, 2026-09-16; blobs > 131072B omitted)
2026-09-16 01:17:21 +05:00

62 lines
1.7 KiB
Go

package jwtverify
import (
"sync"
"testing"
"github.com/centrifugal/centrifugo/v6/internal/config"
"github.com/stretchr/testify/require"
)
// TestVerifierConcurrentReloadRace guards against a data race between token
// verification and a concurrent config reload (SIGHUP). VerifyConnectToken /
// VerifySubscribeToken used to read the verifier's signing/config fields unlocked
// while Reload rewrites them under mu.Lock - a data race that could also nil-deref
// algorithms/jwksManager when a reload switched auth mode. Verification now holds
// verifier.mu.RLock for its whole body. Run with -race.
func TestVerifierConcurrentReloadRace(t *testing.T) {
cfgContainer, err := config.NewContainer(config.DefaultConfig())
require.NoError(t, err)
verifier, err := NewTokenVerifierJWT(VerifierConfig{HMACSecretKey: "secret"}, cfgContainer)
require.NoError(t, err)
done := make(chan struct{})
var writerWg, readersWg sync.WaitGroup
// Writer reloads the verifier config repeatedly, as a SIGHUP would.
writerWg.Add(1)
go func() {
defer writerWg.Done()
configs := []VerifierConfig{
{HMACSecretKey: "secret"},
{HMACSecretKey: "secret2", HMACPreviousSecretKey: "secret"},
{HMACSecretKey: "secret", Audience: "aud", Issuer: "iss"},
}
for i := 0; ; i++ {
select {
case <-done:
return
default:
}
_ = verifier.Reload(configs[i%len(configs)])
}
}()
// Readers verify concurrently; results are irrelevant, only -race matters.
for r := 0; r < 4; r++ {
readersWg.Add(1)
go func() {
defer readersWg.Done()
for i := 0; i < 3000; i++ {
_, _ = verifier.VerifyConnectToken(jwtValid, false)
_, _ = verifier.VerifySubscribeToken(subJWTValidCustomUserClaim, false)
}
}()
}
readersWg.Wait()
close(done)
writerWg.Wait()
}