Files
traefikoidc/token_bench_test.go
lukaszraczylo c474bbafd6 Cleanup [dec2025] (#101)
* Cleanup excessive comments.

* Remove leftovers hanging around from previous refactor

* Improve test coverage
2025-12-09 01:38:02 +00:00

178 lines
4.4 KiB
Go

package traefikoidc
import (
"testing"
"time"
)
// =============================================================================
// TOKEN TYPE DETECTION BENCHMARKS
// =============================================================================
func BenchmarkDetectTokenType(b *testing.B) {
tr := &TraefikOidc{
clientID: "test-client-id",
suppressDiagnosticLogs: true,
tokenTypeCache: NewTestCache(),
}
// Create various JWT test cases
jwtWithNonce := &JWT{
Header: map[string]interface{}{"alg": "RS256"},
Claims: map[string]interface{}{
"nonce": "test-nonce",
"aud": "test-client-id",
"exp": time.Now().Add(1 * time.Hour).Unix(),
},
}
jwtWithScope := &JWT{
Header: map[string]interface{}{"alg": "RS256"},
Claims: map[string]interface{}{
"scope": "openid profile email",
"aud": "some-api",
"exp": time.Now().Add(1 * time.Hour).Unix(),
},
}
jwtComplexDetection := &JWT{
Header: map[string]interface{}{"alg": "RS256", "typ": "JWT"},
Claims: map[string]interface{}{
"aud": []interface{}{"test-client-id", "another-aud"},
"exp": time.Now().Add(1 * time.Hour).Unix(),
"sub": "user123",
"token_type": "Bearer",
"custom_claim": "value",
},
}
testCases := []struct {
name string
jwt *JWT
token string
}{
{"WithNonce", jwtWithNonce, "token-with-nonce-for-benchmark-testing-12345678901234567890"},
{"WithScope", jwtWithScope, "token-with-scope-for-benchmark-testing-12345678901234567890"},
{"ComplexDetection", jwtComplexDetection, "token-complex-for-benchmark-testing-12345678901234567890"},
}
for _, tc := range testCases {
b.Run(tc.name+"_FirstCall", func(b *testing.B) {
// Benchmark first call (uncached)
for i := 0; i < b.N; i++ {
// Clear cache before each iteration
tr.tokenTypeCache.Clear()
_ = tr.detectTokenType(tc.jwt, tc.token)
}
})
b.Run(tc.name+"_Cached", func(b *testing.B) {
// Prime the cache
_ = tr.detectTokenType(tc.jwt, tc.token)
// Benchmark cached calls
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = tr.detectTokenType(tc.jwt, tc.token)
}
})
}
}
// BenchmarkOldDetectionLogic provides comparison with the old implementation logic
func BenchmarkOldDetectionLogic(b *testing.B) {
clientID := "test-client-id"
jwt := &JWT{
Header: map[string]interface{}{"alg": "RS256", "typ": "JWT"},
Claims: map[string]interface{}{
"aud": []interface{}{"test-client-id", "another-aud"},
"exp": time.Now().Add(1 * time.Hour).Unix(),
"sub": "user123",
"token_type": "Bearer",
"custom_claim": "value",
},
}
b.Run("OldLogic", func(b *testing.B) {
for i := 0; i < b.N; i++ {
// Simulate the old detection logic (all 6 sequential checks)
isIDToken := false
isAccessToken := false
// Step 1: Check typ header
if typ, ok := jwt.Header["typ"].(string); ok {
if typ == "at+jwt" {
isAccessToken = true
}
}
// Step 2: Check token_use claim
if !isAccessToken && !isIDToken {
if tokenUse, ok := jwt.Claims["token_use"].(string); ok {
if tokenUse == "access" {
isAccessToken = true
} else if tokenUse == "id" {
isIDToken = true
}
}
}
// Step 3: Check token_type claim
if !isAccessToken && !isIDToken {
if tokenType, ok := jwt.Claims["token_type"].(string); ok {
if tokenType == "access_token" || tokenType == "Bearer" {
isAccessToken = true
} else if tokenType == "id_token" {
isIDToken = true
}
}
}
// Step 4: Check scope claim
if !isAccessToken && !isIDToken {
if scope, ok := jwt.Claims["scope"]; ok {
if _, ok := scope.(string); ok {
isAccessToken = true
}
}
}
// Step 5: Check nonce claim
if !isAccessToken && !isIDToken {
if nonce, ok := jwt.Claims["nonce"]; ok {
if _, ok := nonce.(string); ok {
isIDToken = true
}
}
}
// Step 6: Check audience
if !isAccessToken && !isIDToken {
if aud, ok := jwt.Claims["aud"]; ok {
if audStr, ok := aud.(string); ok && audStr == clientID {
isIDToken = true
}
if audArr, ok := aud.([]interface{}); ok {
for _, v := range audArr {
if str, ok := v.(string); ok && str == clientID {
if len(audArr) == 1 {
isIDToken = true
}
break
}
}
}
}
}
// Step 7: Default to access token
if !isIDToken {
isAccessToken = true
}
_ = isAccessToken
}
})
}