mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-06-05 22:44:17 +00:00
195 lines
5.3 KiB
Go
195 lines
5.3 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestOpaqueTokenDetection tests the detection of opaque tokens vs JWT tokens
|
|
func TestOpaqueTokenDetection(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
token string
|
|
isOpaque bool
|
|
description string
|
|
}{
|
|
{
|
|
name: "JWT token with 3 parts",
|
|
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
|
|
isOpaque: false,
|
|
description: "Standard JWT with header.payload.signature",
|
|
},
|
|
{
|
|
name: "Auth0 opaque token",
|
|
token: "8n3d84nd92nf92nf92nf92nf923nf923nf923nf9",
|
|
isOpaque: true,
|
|
description: "Auth0 opaque access token",
|
|
},
|
|
{
|
|
name: "Okta opaque token",
|
|
token: "00Otkjhgt5Rfasde12345678901234567890",
|
|
isOpaque: true,
|
|
description: "Okta opaque access token",
|
|
},
|
|
{
|
|
name: "AWS Cognito opaque token",
|
|
token: "AGPAYJhZmU3NzI5YTQtNGQ0Yy00YTU5LWJjYTQtYzdlMzQ0MmQ3ZDJl",
|
|
isOpaque: true,
|
|
description: "AWS Cognito opaque access token",
|
|
},
|
|
{
|
|
name: "Invalid single dot token",
|
|
token: "invalid.token",
|
|
isOpaque: true, // Treated as opaque since it's not a valid JWT
|
|
description: "Invalid format with single dot",
|
|
},
|
|
{
|
|
name: "Token with no dots",
|
|
token: "opaquetoken1234567890abcdefghijklmnop",
|
|
isOpaque: true,
|
|
description: "Pure opaque token with no dots",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Check dot count to determine if token is opaque
|
|
dotCount := strings.Count(tt.token, ".")
|
|
isOpaqueToken := dotCount != 2
|
|
|
|
if isOpaqueToken != tt.isOpaque {
|
|
t.Errorf("Token detection failed for %s: expected opaque=%v, got opaque=%v (dots=%d)",
|
|
tt.name, tt.isOpaque, isOpaqueToken, dotCount)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestOpaqueTokenValidation tests the validation logic for opaque tokens
|
|
func TestOpaqueTokenValidation(t *testing.T) {
|
|
logger := GetSingletonNoOpLogger()
|
|
cm := NewChunkManager(logger)
|
|
defer cm.Shutdown()
|
|
|
|
tests := []struct {
|
|
name string
|
|
token string
|
|
wantError bool
|
|
}{
|
|
{
|
|
name: "Valid opaque token",
|
|
token: "opaquetoken1234567890abcdefghijklmnop",
|
|
wantError: false,
|
|
},
|
|
{
|
|
name: "Too short opaque token",
|
|
token: "short",
|
|
wantError: true, // Less than 20 characters
|
|
},
|
|
{
|
|
name: "Opaque token with spaces",
|
|
token: "opaque token with spaces 1234567890",
|
|
wantError: true, // Contains spaces
|
|
},
|
|
{
|
|
name: "Valid JWT token",
|
|
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
|
|
wantError: false,
|
|
},
|
|
}
|
|
|
|
config := TokenConfig{
|
|
Type: "access",
|
|
MinLength: 5,
|
|
MaxLength: 100 * 1024,
|
|
MaxChunks: 25,
|
|
MaxChunkSize: maxCookieSize,
|
|
AllowOpaqueTokens: true,
|
|
RequireJWTFormat: false,
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := cm.validateToken(tt.token, config)
|
|
hasError := result.Error != nil
|
|
|
|
if hasError != tt.wantError {
|
|
if tt.wantError {
|
|
t.Errorf("Expected error for %s but got none", tt.name)
|
|
} else {
|
|
t.Errorf("Unexpected error for %s: %v", tt.name, result.Error)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestOpaqueTokenStorage tests that opaque tokens are properly detected and stored
|
|
func TestOpaqueTokenStorage(t *testing.T) {
|
|
// Test the token format detection logic
|
|
tests := []struct {
|
|
name string
|
|
token string
|
|
shouldStore bool
|
|
description string
|
|
}{
|
|
{
|
|
name: "Valid opaque token",
|
|
token: "auth0_opaque_token_1234567890abcdefghijklmnop",
|
|
shouldStore: true,
|
|
description: "Opaque token with sufficient length and no dots",
|
|
},
|
|
{
|
|
name: "Valid JWT token",
|
|
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
|
|
shouldStore: true,
|
|
description: "Standard JWT with three parts",
|
|
},
|
|
{
|
|
name: "Invalid single-dot token",
|
|
token: "invalid.token",
|
|
shouldStore: false,
|
|
description: "Token with single dot - invalid format",
|
|
},
|
|
{
|
|
name: "Too short opaque token",
|
|
token: "short",
|
|
shouldStore: false,
|
|
description: "Opaque token too short (less than 20 chars)",
|
|
},
|
|
{
|
|
name: "Multi-dot invalid token",
|
|
token: "too.many.dots.here",
|
|
shouldStore: false,
|
|
description: "Token with more than 2 dots - invalid format",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Simulate the validation logic from SetAccessToken
|
|
shouldStore := true
|
|
if tt.token != "" {
|
|
dotCount := strings.Count(tt.token, ".")
|
|
// Reject tokens with exactly 1 dot (invalid format)
|
|
if dotCount == 1 {
|
|
shouldStore = false
|
|
}
|
|
// For opaque tokens (no dots), ensure minimum length
|
|
if dotCount == 0 && len(tt.token) < 20 {
|
|
shouldStore = false
|
|
}
|
|
// Tokens with more than 2 dots are also invalid
|
|
if dotCount > 2 {
|
|
shouldStore = false
|
|
}
|
|
}
|
|
|
|
if shouldStore != tt.shouldStore {
|
|
t.Errorf("Token storage decision failed for %s: expected store=%v, got store=%v",
|
|
tt.name, tt.shouldStore, shouldStore)
|
|
}
|
|
})
|
|
}
|
|
}
|