mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-20 04:57:02 +00:00
Add ability to set cookie max age - issue #91
This commit is contained in:
@@ -110,6 +110,7 @@ testData:
|
|||||||
enablePKCE: false # Enables PKCE (Proof Key for Code Exchange) for additional security
|
enablePKCE: false # Enables PKCE (Proof Key for Code Exchange) for additional security
|
||||||
cookieDomain: "" # Explicit domain for session cookies (e.g., ".example.com" for multi-subdomain setups)
|
cookieDomain: "" # Explicit domain for session cookies (e.g., ".example.com" for multi-subdomain setups)
|
||||||
cookiePrefix: "" # Custom prefix for cookie names (e.g., "_oidc_myapp_" for session isolation between middleware instances)
|
cookiePrefix: "" # Custom prefix for cookie names (e.g., "_oidc_myapp_" for session isolation between middleware instances)
|
||||||
|
sessionMaxAge: 86400 # Maximum session age in seconds (default: 86400 = 24 hours, 0 = use default)
|
||||||
overrideScopes: false # When true, replaces default scopes instead of appending (default: false)
|
overrideScopes: false # When true, replaces default scopes instead of appending (default: false)
|
||||||
refreshGracePeriodSeconds: 60 # Seconds before token expiry to attempt proactive refresh (default: 60)
|
refreshGracePeriodSeconds: 60 # Seconds before token expiry to attempt proactive refresh (default: 60)
|
||||||
|
|
||||||
@@ -693,6 +694,45 @@ configuration:
|
|||||||
See: https://github.com/lukaszraczylo/traefikoidc/issues/87
|
See: https://github.com/lukaszraczylo/traefikoidc/issues/87
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
|
sessionMaxAge:
|
||||||
|
type: integer
|
||||||
|
description: |
|
||||||
|
Maximum session age in seconds before requiring re-authentication.
|
||||||
|
|
||||||
|
This setting controls how long a user's authentication session remains valid
|
||||||
|
before they must authenticate again through the OIDC provider. The session
|
||||||
|
age is tracked from the initial authentication time (created_at).
|
||||||
|
|
||||||
|
When a session exceeds this age:
|
||||||
|
- The session is cleared and invalidated
|
||||||
|
- The user is redirected to re-authenticate
|
||||||
|
- All session cookies are removed
|
||||||
|
|
||||||
|
Use Cases:
|
||||||
|
- High-security applications: Use shorter durations (e.g., 3600 = 1 hour)
|
||||||
|
- Standard applications: Default 24 hours balances security and UX
|
||||||
|
- Long-lived sessions: Extend for applications accessed infrequently
|
||||||
|
(e.g., 604800 = 7 days, 2592000 = 30 days)
|
||||||
|
|
||||||
|
Security Considerations:
|
||||||
|
- Shorter sessions provide better security but require more frequent logins
|
||||||
|
- Longer sessions improve user experience but increase security risk
|
||||||
|
- Consider your application's security requirements and user access patterns
|
||||||
|
- This is independent of token refresh - tokens can be refreshed during the session
|
||||||
|
|
||||||
|
Common Values:
|
||||||
|
- 3600 (1 hour) - High security applications
|
||||||
|
- 28800 (8 hours) - Working day session
|
||||||
|
- 86400 (24 hours) - Default, balances security and convenience
|
||||||
|
- 604800 (7 days) - Weekly session for less frequently accessed apps
|
||||||
|
- 2592000 (30 days) - Monthly session for infrequently used applications
|
||||||
|
|
||||||
|
Default: 86400 (24 hours)
|
||||||
|
Minimum: 0 (uses default of 24 hours)
|
||||||
|
|
||||||
|
See: https://github.com/lukaszraczylo/traefikoidc/issues/91
|
||||||
|
required: false
|
||||||
|
|
||||||
overrideScopes:
|
overrideScopes:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ The middleware supports the following configuration options:
|
|||||||
| `refreshGracePeriodSeconds` | Seconds before token expiry to attempt proactive refresh | `60` | `120` |
|
| `refreshGracePeriodSeconds` | Seconds before token expiry to attempt proactive refresh | `60` | `120` |
|
||||||
| `cookieDomain` | Explicit domain for session cookies (important for multi-subdomain setups) | auto-detected | `.example.com`, `app.example.com` |
|
| `cookieDomain` | Explicit domain for session cookies (important for multi-subdomain setups) | auto-detected | `.example.com`, `app.example.com` |
|
||||||
| `cookiePrefix` | Custom prefix for session cookie names (for isolating multiple middleware instances) | `_oidc_raczylo_` | `_oidc_userauth_`, `_oidc_admin_` |
|
| `cookiePrefix` | Custom prefix for session cookie names (for isolating multiple middleware instances) | `_oidc_raczylo_` | `_oidc_userauth_`, `_oidc_admin_` |
|
||||||
|
| `sessionMaxAge` | Maximum session age in seconds before requiring re-authentication | `86400` (24 hours) | `3600` (1 hour), `604800` (7 days) |
|
||||||
| `audience` | Custom audience for access token validation (for Auth0 custom APIs, etc.) | `clientID` | `https://my-api.example.com` |
|
| `audience` | Custom audience for access token validation (for Auth0 custom APIs, etc.) | `clientID` | `https://my-api.example.com` |
|
||||||
| `strictAudienceValidation` | Reject sessions with access token audience mismatch (prevents token confusion attacks) | `false` | `true` |
|
| `strictAudienceValidation` | Reject sessions with access token audience mismatch (prevents token confusion attacks) | `false` | `true` |
|
||||||
| `allowOpaqueTokens` | Enable opaque (non-JWT) access token support via RFC 7662 introspection | `false` | `true` |
|
| `allowOpaqueTokens` | Enable opaque (non-JWT) access token support via RFC 7662 introspection | `false` | `true` |
|
||||||
@@ -934,6 +935,39 @@ spec:
|
|||||||
|
|
||||||
This configuration prevents authorization bypass issues where a user authenticated via the general middleware could access admin-protected routes. See [issue #87](https://github.com/lukaszraczylo/traefikoidc/issues/87) for more details.
|
This configuration prevents authorization bypass issues where a user authenticated via the general middleware could access admin-protected routes. See [issue #87](https://github.com/lukaszraczylo/traefikoidc/issues/87) for more details.
|
||||||
|
|
||||||
|
### With Extended Session Duration
|
||||||
|
|
||||||
|
For applications that users access infrequently (weekly or monthly), you can extend the session duration beyond the default 24 hours to reduce authentication friction:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: oidc-long-session
|
||||||
|
namespace: traefik
|
||||||
|
spec:
|
||||||
|
plugin:
|
||||||
|
traefikoidc:
|
||||||
|
providerURL: https://auth.example.com
|
||||||
|
clientID: your-client-id
|
||||||
|
clientSecret: your-client-secret
|
||||||
|
sessionEncryptionKey: your-key-at-least-32-bytes-long
|
||||||
|
callbackURL: /oauth2/callback
|
||||||
|
sessionMaxAge: 604800 # 7 days (in seconds)
|
||||||
|
# Other common values:
|
||||||
|
# 259200 - 3 days
|
||||||
|
# 604800 - 7 days
|
||||||
|
# 1209600 - 14 days
|
||||||
|
# 2592000 - 30 days
|
||||||
|
```
|
||||||
|
|
||||||
|
**Security Note**: Longer session durations improve user experience but increase security risk. Consider your application's security requirements:
|
||||||
|
- **High-security apps**: Use shorter sessions (3600 = 1 hour)
|
||||||
|
- **Standard apps**: Default 24 hours balances security and UX
|
||||||
|
- **Low-frequency access apps**: Extend to 7-30 days for better UX
|
||||||
|
|
||||||
|
See [issue #91](https://github.com/lukaszraczylo/traefikoidc/issues/91) for more details.
|
||||||
|
|
||||||
### With Custom Logging and Rate Limiting
|
### With Custom Logging and Rate Limiting
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -838,7 +838,7 @@ func TestAudienceEndToEndScenario(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager(strings.Repeat("a", MinSessionEncryptionKeyLength), false, "", "", logger)
|
sm, err := NewSessionManager(strings.Repeat("a", MinSessionEncryptionKeyLength), false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -79,7 +79,7 @@ func TestAzureOIDCRegression(t *testing.T) {
|
|||||||
tOidc := &mockTraefikOidc{TraefikOidc: baseOidc}
|
tOidc := &mockTraefikOidc{TraefikOidc: baseOidc}
|
||||||
|
|
||||||
// Initialize session manager
|
// Initialize session manager
|
||||||
sessionManager, _ := NewSessionManager("test-encryption-key-32-bytes-long", false, "", "", mockLogger)
|
sessionManager, _ := NewSessionManager("test-encryption-key-32-bytes-long", false, "", "", 0, mockLogger)
|
||||||
tOidc.sessionManager = sessionManager
|
tOidc.sessionManager = sessionManager
|
||||||
|
|
||||||
// Mock the JWT verification to avoid JWKS lookup issues
|
// Mock the JWT verification to avoid JWKS lookup issues
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func TestCSRFTokenSessionManagement(t *testing.T) {
|
|||||||
// Test that CSRF tokens persist through the authentication flow
|
// Test that CSRF tokens persist through the authentication flow
|
||||||
t.Run("CSRF_Token_Persists_After_Selective_Clear", func(t *testing.T) {
|
t.Run("CSRF_Token_Persists_After_Selective_Clear", func(t *testing.T) {
|
||||||
// Create a session manager
|
// Create a session manager
|
||||||
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", NewLogger("debug"))
|
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create initial request
|
// Create initial request
|
||||||
@@ -90,7 +90,7 @@ func TestCSRFTokenSessionManagement(t *testing.T) {
|
|||||||
|
|
||||||
// Test that marking session as dirty forces save
|
// Test that marking session as dirty forces save
|
||||||
t.Run("Mark_Dirty_Forces_Session_Save", func(t *testing.T) {
|
t.Run("Mark_Dirty_Forces_Session_Save", func(t *testing.T) {
|
||||||
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", NewLogger("debug"))
|
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://example.com/test", nil)
|
req := httptest.NewRequest("GET", "http://example.com/test", nil)
|
||||||
@@ -126,7 +126,7 @@ func TestCSRFTokenSessionManagement(t *testing.T) {
|
|||||||
|
|
||||||
// Test Azure-specific session handling
|
// Test Azure-specific session handling
|
||||||
t.Run("Azure_Session_Cookie_Configuration", func(t *testing.T) {
|
t.Run("Azure_Session_Cookie_Configuration", func(t *testing.T) {
|
||||||
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", NewLogger("debug"))
|
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Simulate Azure callback scenario
|
// Simulate Azure callback scenario
|
||||||
@@ -158,7 +158,7 @@ func TestCSRFTokenSessionManagement(t *testing.T) {
|
|||||||
|
|
||||||
// Test session continuity through auth flow
|
// Test session continuity through auth flow
|
||||||
t.Run("Session_Continuity_Through_Auth_Flow", func(t *testing.T) {
|
t.Run("Session_Continuity_Through_Auth_Flow", func(t *testing.T) {
|
||||||
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", NewLogger("debug"))
|
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Step 1: Initial request
|
// Step 1: Initial request
|
||||||
@@ -199,7 +199,7 @@ func TestCSRFTokenSessionManagement(t *testing.T) {
|
|||||||
|
|
||||||
// Test large token handling doesn't affect CSRF
|
// Test large token handling doesn't affect CSRF
|
||||||
t.Run("Large_Tokens_Dont_Affect_CSRF", func(t *testing.T) {
|
t.Run("Large_Tokens_Dont_Affect_CSRF", func(t *testing.T) {
|
||||||
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", NewLogger("debug"))
|
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://example.com/test", nil)
|
req := httptest.NewRequest("GET", "http://example.com/test", nil)
|
||||||
@@ -262,7 +262,7 @@ func TestAuthFlowWithoutExternalDependencies(t *testing.T) {
|
|||||||
|
|
||||||
// We can't fully initialize TraefikOidc without network access,
|
// We can't fully initialize TraefikOidc without network access,
|
||||||
// but we can test the session management directly
|
// but we can test the session management directly
|
||||||
sessionManager, err := NewSessionManager(plugin.SessionEncryptionKey, plugin.ForceHTTPS, "", "", NewLogger(plugin.LogLevel))
|
sessionManager, err := NewSessionManager(plugin.SessionEncryptionKey, plugin.ForceHTTPS, "", "", 0, NewLogger(plugin.LogLevel))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("Session_Created_On_Protected_Request", func(t *testing.T) {
|
t.Run("Session_Created_On_Protected_Request", func(t *testing.T) {
|
||||||
@@ -291,7 +291,7 @@ func TestAuthFlowWithoutExternalDependencies(t *testing.T) {
|
|||||||
// TestRegressionLoginLoop specifically tests the fix for issue #53
|
// TestRegressionLoginLoop specifically tests the fix for issue #53
|
||||||
func TestRegressionLoginLoop(t *testing.T) {
|
func TestRegressionLoginLoop(t *testing.T) {
|
||||||
// This test verifies that the specific changes made to fix the login loop work correctly
|
// This test verifies that the specific changes made to fix the login loop work correctly
|
||||||
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", NewLogger("debug"))
|
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Simulate the exact flow that was causing the login loop
|
// Simulate the exact flow that was causing the login loop
|
||||||
@@ -392,7 +392,7 @@ func TestRegressionLoginLoop(t *testing.T) {
|
|||||||
|
|
||||||
// TestCSRFValidationTiming tests timing-sensitive CSRF validation scenarios
|
// TestCSRFValidationTiming tests timing-sensitive CSRF validation scenarios
|
||||||
func TestCSRFValidationTiming(t *testing.T) {
|
func TestCSRFValidationTiming(t *testing.T) {
|
||||||
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", NewLogger("debug"))
|
sessionManager, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("Rapid_Redirect_Maintains_CSRF", func(t *testing.T) {
|
t.Run("Rapid_Redirect_Maintains_CSRF", func(t *testing.T) {
|
||||||
|
|||||||
@@ -226,7 +226,9 @@ func NewWithContext(ctx context.Context, config *Config, next http.Handler, name
|
|||||||
t.logger.Debugf("No custom audience specified, using clientID as audience: %s", t.clientID)
|
t.logger.Debugf("No custom audience specified, using clientID as audience: %s", t.clientID)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.sessionManager, _ = NewSessionManager(config.SessionEncryptionKey, config.ForceHTTPS, config.CookieDomain, config.CookiePrefix, t.logger) // Safe to ignore: session manager creation with fallback to defaults
|
// Convert sessionMaxAge from seconds to duration (0 will use default 24 hours)
|
||||||
|
sessionMaxAge := time.Duration(config.SessionMaxAge) * time.Second
|
||||||
|
t.sessionManager, _ = NewSessionManager(config.SessionEncryptionKey, config.ForceHTTPS, config.CookieDomain, config.CookiePrefix, sessionMaxAge, t.logger) // Safe to ignore: session manager creation with fallback to defaults
|
||||||
t.errorRecoveryManager = NewErrorRecoveryManager(t.logger)
|
t.errorRecoveryManager = NewErrorRecoveryManager(t.logger)
|
||||||
|
|
||||||
// Initialize token resilience manager with default configuration
|
// Initialize token resilience manager with default configuration
|
||||||
|
|||||||
@@ -539,7 +539,7 @@ func (m *MockSessionData) Clear(r *http.Request, w http.ResponseWriter) error {
|
|||||||
|
|
||||||
// Helper function to create a test session manager
|
// Helper function to create a test session manager
|
||||||
func createTestSessionManager(t *testing.T) *SessionManager {
|
func createTestSessionManager(t *testing.T) *SessionManager {
|
||||||
sm, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", NewLogger("debug"))
|
sm, err := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, NewLogger("debug"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -104,7 +104,7 @@ func (ts *TestSuite) Setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger := NewLogger("info")
|
logger := NewLogger("info")
|
||||||
ts.sessionManager, _ = NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", logger)
|
ts.sessionManager, _ = NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", 0, logger)
|
||||||
|
|
||||||
// Create WaitGroup for the OIDC instance
|
// Create WaitGroup for the OIDC instance
|
||||||
goroutineWG := &sync.WaitGroup{}
|
goroutineWG := &sync.WaitGroup{}
|
||||||
@@ -1274,7 +1274,7 @@ func TestHandleCallback(t *testing.T) {
|
|||||||
ts.tOidc.tokenBlacklist = NewCache() // Use generic cache for blacklist
|
ts.tOidc.tokenBlacklist = NewCache() // Use generic cache for blacklist
|
||||||
|
|
||||||
logger := NewLogger("info")
|
logger := NewLogger("info")
|
||||||
sessionManager, _ := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", logger)
|
sessionManager, _ := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", 0, logger)
|
||||||
|
|
||||||
// Create a new instance for each test to avoid state carryover
|
// Create a new instance for each test to avoid state carryover
|
||||||
instanceExtractClaimsFunc := tc.extractClaimsFunc
|
instanceExtractClaimsFunc := tc.extractClaimsFunc
|
||||||
@@ -1663,7 +1663,7 @@ func TestHandleLogout(t *testing.T) {
|
|||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
logger := NewLogger("info")
|
logger := NewLogger("info")
|
||||||
sessionManager, _ := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", logger)
|
sessionManager, _ := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", 0, logger)
|
||||||
tOidc := &TraefikOidc{
|
tOidc := &TraefikOidc{
|
||||||
revocationURL: mockRevocationServer.URL,
|
revocationURL: mockRevocationServer.URL,
|
||||||
endSessionURL: tc.endSessionURL,
|
endSessionURL: tc.endSessionURL,
|
||||||
@@ -1966,7 +1966,7 @@ func TestHandleExpiredToken(t *testing.T) {
|
|||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
logger := NewLogger("info")
|
logger := NewLogger("info")
|
||||||
sessionManager, _ := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", logger)
|
sessionManager, _ := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", 0, logger)
|
||||||
|
|
||||||
tOidc := &TraefikOidc{
|
tOidc := &TraefikOidc{
|
||||||
sessionManager: sessionManager,
|
sessionManager: sessionManager,
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ func TestMemoryLeakConsolidated(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
0,
|
||||||
tf.logger,
|
tf.logger,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -295,6 +296,7 @@ func TestMemoryLeakConsolidated(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
0,
|
||||||
tf.logger,
|
tf.logger,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
@@ -698,6 +700,7 @@ func BenchmarkMemoryUsage(b *testing.B) {
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
0,
|
||||||
NewLogger("error"),
|
NewLogger("error"),
|
||||||
)
|
)
|
||||||
// No Cleanup method, defer not needed
|
// No Cleanup method, defer not needed
|
||||||
@@ -778,6 +781,7 @@ func TestGoroutineLeaks(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
0,
|
||||||
NewLogger("error"),
|
NewLogger("error"),
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -868,6 +872,7 @@ func TestMemoryThresholds(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
0,
|
||||||
NewLogger("error"),
|
NewLogger("error"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -65,7 +65,7 @@ func TestMemoryTestOrchestrator(t *testing.T) {
|
|||||||
mto := NewMemoryTestOrchestrator(config, logger)
|
mto := NewMemoryTestOrchestrator(config, logger)
|
||||||
|
|
||||||
// Test registering a component
|
// Test registering a component
|
||||||
sessionManager, err := NewSessionManager("test-key-32-chars-long-for-testing", false, "", "", logger)
|
sessionManager, err := NewSessionManager("test-key-32-chars-long-for-testing", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ func TestComponentProfilers(t *testing.T) {
|
|||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
|
|
||||||
// Test Session Pool Profiler
|
// Test Session Pool Profiler
|
||||||
sessionManager, err := NewSessionManager("test-key-32-chars-long-for-testing", false, "", "", logger)
|
sessionManager, err := NewSessionManager("test-key-32-chars-long-for-testing", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func testIssue53CSRFRegression(t *testing.T) {
|
|||||||
// 3. Session cookies must be properly configured for HTTPS
|
// 3. Session cookies must be properly configured for HTTPS
|
||||||
// 4. CSRF token must persist through the OAuth flow
|
// 4. CSRF token must persist through the OAuth flow
|
||||||
|
|
||||||
sessionManager, err := traefikoidc.NewSessionManager("test-encryption-key-32-characters", false, "", "", traefikoidc.NewLogger("debug"))
|
sessionManager, err := traefikoidc.NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, traefikoidc.NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Step 1: Initial request to protected resource
|
// Step 1: Initial request to protected resource
|
||||||
@@ -116,7 +116,7 @@ func testIssue53CSRFRegression(t *testing.T) {
|
|||||||
|
|
||||||
// testIssue53ReverseProxyHTTPS tests HTTPS detection in reverse proxy setups
|
// testIssue53ReverseProxyHTTPS tests HTTPS detection in reverse proxy setups
|
||||||
func testIssue53ReverseProxyHTTPS(t *testing.T) {
|
func testIssue53ReverseProxyHTTPS(t *testing.T) {
|
||||||
sessionManager, err := traefikoidc.NewSessionManager("test-encryption-key-32-characters", false, "", "", traefikoidc.NewLogger("debug"))
|
sessionManager, err := traefikoidc.NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, traefikoidc.NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create authenticated session with Azure tokens
|
// Create authenticated session with Azure tokens
|
||||||
@@ -200,7 +200,7 @@ func testIssue53SameSiteCookies(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
sessionManager, err := traefikoidc.NewSessionManager("test-encryption-key-32-characters", false, "", "", traefikoidc.NewLogger("debug"))
|
sessionManager, err := traefikoidc.NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, traefikoidc.NewLogger("debug"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "http://internal/test", nil)
|
req := httptest.NewRequest("GET", "http://internal/test", nil)
|
||||||
|
|||||||
@@ -468,7 +468,7 @@ func TestSessionFixationAttack(t *testing.T) {
|
|||||||
tc := newTestCleanup(t)
|
tc := newTestCleanup(t)
|
||||||
|
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", logger)
|
sm, err := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -625,7 +625,7 @@ func TestSessionFixationAttack(t *testing.T) {
|
|||||||
// TestCSRFProtection tests CSRF protection in POST requests
|
// TestCSRFProtection tests CSRF protection in POST requests
|
||||||
func TestCSRFProtection(t *testing.T) {
|
func TestCSRFProtection(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", logger)
|
sm, err := NewSessionManager("test-secret-key-that-is-at-least-32-bytes", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-15
@@ -237,7 +237,8 @@ type SessionManager struct {
|
|||||||
logger *Logger
|
logger *Logger
|
||||||
chunkManager *ChunkManager
|
chunkManager *ChunkManager
|
||||||
cookieDomain string
|
cookieDomain string
|
||||||
cookiePrefix string // Prefix for cookie names (default: "_oidc_raczylo_")
|
cookiePrefix string // Prefix for cookie names (default: "_oidc_raczylo_")
|
||||||
|
sessionMaxAge time.Duration // Maximum session age (default: 24 hours)
|
||||||
cleanupMutex sync.RWMutex
|
cleanupMutex sync.RWMutex
|
||||||
forceHTTPS bool
|
forceHTTPS bool
|
||||||
cleanupDone bool
|
cleanupDone bool
|
||||||
@@ -258,12 +259,13 @@ type SessionManager struct {
|
|||||||
// - forceHTTPS: Whether to force HTTPS-only cookies regardless of request scheme.
|
// - forceHTTPS: Whether to force HTTPS-only cookies regardless of request scheme.
|
||||||
// - cookieDomain: The domain for session cookies (empty for auto-detection).
|
// - cookieDomain: The domain for session cookies (empty for auto-detection).
|
||||||
// - cookiePrefix: Prefix for session cookie names (empty for default "_oidc_raczylo_").
|
// - cookiePrefix: Prefix for session cookie names (empty for default "_oidc_raczylo_").
|
||||||
|
// - sessionMaxAge: Maximum session age duration (0 for default 24 hours).
|
||||||
// - logger: Logger instance for debug and error logging.
|
// - logger: Logger instance for debug and error logging.
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// - The configured SessionManager instance.
|
// - The configured SessionManager instance.
|
||||||
// - An error if the encryption key does not meet minimum length requirements.
|
// - An error if the encryption key does not meet minimum length requirements.
|
||||||
func NewSessionManager(encryptionKey string, forceHTTPS bool, cookieDomain string, cookiePrefix string, logger *Logger) (*SessionManager, error) {
|
func NewSessionManager(encryptionKey string, forceHTTPS bool, cookieDomain string, cookiePrefix string, sessionMaxAge time.Duration, logger *Logger) (*SessionManager, error) {
|
||||||
if len(encryptionKey) < minEncryptionKeyLength {
|
if len(encryptionKey) < minEncryptionKeyLength {
|
||||||
return nil, fmt.Errorf("encryption key must be at least %d bytes long", minEncryptionKeyLength)
|
return nil, fmt.Errorf("encryption key must be at least %d bytes long", minEncryptionKeyLength)
|
||||||
}
|
}
|
||||||
@@ -273,17 +275,23 @@ func NewSessionManager(encryptionKey string, forceHTTPS bool, cookieDomain strin
|
|||||||
cookiePrefix = "_oidc_raczylo_"
|
cookiePrefix = "_oidc_raczylo_"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set default session max age if not provided (24 hours for backward compatibility)
|
||||||
|
if sessionMaxAge == 0 {
|
||||||
|
sessionMaxAge = absoluteSessionTimeout
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
sm := &SessionManager{
|
sm := &SessionManager{
|
||||||
store: sessions.NewCookieStore([]byte(encryptionKey)),
|
store: sessions.NewCookieStore([]byte(encryptionKey)),
|
||||||
forceHTTPS: forceHTTPS,
|
forceHTTPS: forceHTTPS,
|
||||||
cookieDomain: cookieDomain,
|
cookieDomain: cookieDomain,
|
||||||
cookiePrefix: cookiePrefix,
|
cookiePrefix: cookiePrefix,
|
||||||
logger: logger,
|
sessionMaxAge: sessionMaxAge,
|
||||||
chunkManager: NewChunkManager(logger),
|
logger: logger,
|
||||||
ctx: ctx,
|
chunkManager: NewChunkManager(logger),
|
||||||
cancel: cancel,
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize global memory monitoring (singleton)
|
// Initialize global memory monitoring (singleton)
|
||||||
@@ -615,7 +623,7 @@ func (sm *SessionManager) GetSessionMetrics() map[string]interface{} {
|
|||||||
metrics := make(map[string]interface{})
|
metrics := make(map[string]interface{})
|
||||||
metrics["session_manager_type"] = "CookieStore"
|
metrics["session_manager_type"] = "CookieStore"
|
||||||
metrics["force_https"] = sm.forceHTTPS
|
metrics["force_https"] = sm.forceHTTPS
|
||||||
metrics["absolute_timeout_hours"] = absoluteSessionTimeout.Hours()
|
metrics["absolute_timeout_hours"] = sm.sessionMaxAge.Hours()
|
||||||
metrics["max_cookie_size"] = maxCookieSize
|
metrics["max_cookie_size"] = maxCookieSize
|
||||||
metrics["max_browser_cookie_size"] = maxBrowserCookieSize
|
metrics["max_browser_cookie_size"] = maxBrowserCookieSize
|
||||||
|
|
||||||
@@ -649,7 +657,7 @@ func (sm *SessionManager) EnhanceSessionSecurity(options *sessions.Options, r *h
|
|||||||
userAgent := r.Header.Get("User-Agent")
|
userAgent := r.Header.Get("User-Agent")
|
||||||
if userAgent == "" {
|
if userAgent == "" {
|
||||||
sm.logger.Debugf("Request from %s missing User-Agent header", r.RemoteAddr)
|
sm.logger.Debugf("Request from %s missing User-Agent header", r.RemoteAddr)
|
||||||
options.MaxAge = int((absoluteSessionTimeout / 2).Seconds())
|
options.MaxAge = int((sm.sessionMaxAge / 2).Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Header.Get("X-Forwarded-Proto") == "https" || r.TLS != nil || sm.forceHTTPS {
|
if r.Header.Get("X-Forwarded-Proto") == "https" || r.TLS != nil || sm.forceHTTPS {
|
||||||
@@ -699,7 +707,7 @@ func (sm *SessionManager) getSessionOptions(isSecure bool) *sessions.Options {
|
|||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Secure: isSecure || sm.forceHTTPS,
|
Secure: isSecure || sm.forceHTTPS,
|
||||||
SameSite: http.SameSiteLaxMode,
|
SameSite: http.SameSiteLaxMode,
|
||||||
MaxAge: int(absoluteSessionTimeout.Seconds()),
|
MaxAge: int(sm.sessionMaxAge.Seconds()),
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Domain: sm.cookieDomain,
|
Domain: sm.cookieDomain,
|
||||||
}
|
}
|
||||||
@@ -829,7 +837,7 @@ func (sm *SessionManager) GetSession(r *http.Request) (*SessionData, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if createdAt, ok := sessionData.mainSession.Values["created_at"].(int64); ok {
|
if createdAt, ok := sessionData.mainSession.Values["created_at"].(int64); ok {
|
||||||
if time.Since(time.Unix(createdAt, 0)) > absoluteSessionTimeout {
|
if time.Since(time.Unix(createdAt, 0)) > sm.sessionMaxAge {
|
||||||
_ = sessionData.Clear(r, nil) // Safe to ignore: session is being invalidated
|
_ = sessionData.Clear(r, nil) // Safe to ignore: session is being invalidated
|
||||||
return handleError(fmt.Errorf("session timeout"), "session expired")
|
return handleError(fmt.Errorf("session timeout"), "session expired")
|
||||||
}
|
}
|
||||||
@@ -1138,7 +1146,7 @@ func (sd *SessionData) getAuthenticatedUnsafe() bool {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return time.Since(time.Unix(createdAt, 0)) <= absoluteSessionTimeout
|
return time.Since(time.Unix(createdAt, 0)) <= sd.manager.sessionMaxAge
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAuthenticated sets the authentication status and manages session security.
|
// SetAuthenticated sets the authentication status and manages session security.
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ func TestCookiePrefix(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
tt.cookiePrefix,
|
tt.cookiePrefix,
|
||||||
|
0,
|
||||||
logger,
|
logger,
|
||||||
chunkManager,
|
chunkManager,
|
||||||
)
|
)
|
||||||
@@ -87,6 +88,7 @@ func TestMultipleInstancesWithDifferentPrefixes(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
"example.com",
|
"example.com",
|
||||||
"_oidc_app1_",
|
"_oidc_app1_",
|
||||||
|
0,
|
||||||
logger,
|
logger,
|
||||||
chunkManager1,
|
chunkManager1,
|
||||||
)
|
)
|
||||||
@@ -99,6 +101,7 @@ func TestMultipleInstancesWithDifferentPrefixes(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
"example.com",
|
"example.com",
|
||||||
"_oidc_app2_",
|
"_oidc_app2_",
|
||||||
|
0,
|
||||||
logger,
|
logger,
|
||||||
chunkManager2,
|
chunkManager2,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,15 +18,16 @@ const (
|
|||||||
|
|
||||||
// SessionManager handles session creation, management and cleanup
|
// SessionManager handles session creation, management and cleanup
|
||||||
type SessionManager struct {
|
type SessionManager struct {
|
||||||
sessionPool sync.Pool
|
sessionPool sync.Pool
|
||||||
store sessions.Store
|
store sessions.Store
|
||||||
logger Logger
|
logger Logger
|
||||||
chunkManager ChunkManager
|
chunkManager ChunkManager
|
||||||
cookieDomain string
|
cookieDomain string
|
||||||
cookiePrefix string // Prefix for cookie names (default: "_oidc_raczylo_")
|
cookiePrefix string // Prefix for cookie names (default: "_oidc_raczylo_")
|
||||||
cleanupMutex sync.RWMutex
|
sessionMaxAge time.Duration // Maximum session age (default: 24 hours)
|
||||||
forceHTTPS bool
|
cleanupMutex sync.RWMutex
|
||||||
cleanupDone bool
|
forceHTTPS bool
|
||||||
|
cleanupDone bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logger interface for dependency injection
|
// Logger interface for dependency injection
|
||||||
@@ -70,7 +71,7 @@ type SessionData interface {
|
|||||||
// NewSessionManager creates a new SessionManager instance with secure defaults.
|
// NewSessionManager creates a new SessionManager instance with secure defaults.
|
||||||
// It initializes the cookie store with encryption, sets up session pooling,
|
// It initializes the cookie store with encryption, sets up session pooling,
|
||||||
// and configures chunk management for large tokens.
|
// and configures chunk management for large tokens.
|
||||||
func NewSessionManager(encryptionKey string, forceHTTPS bool, cookieDomain string, cookiePrefix string, logger Logger, chunkManager ChunkManager) (*SessionManager, error) {
|
func NewSessionManager(encryptionKey string, forceHTTPS bool, cookieDomain string, cookiePrefix string, sessionMaxAge time.Duration, logger Logger, chunkManager ChunkManager) (*SessionManager, error) {
|
||||||
if len(encryptionKey) < minEncryptionKeyLength {
|
if len(encryptionKey) < minEncryptionKeyLength {
|
||||||
return nil, fmt.Errorf("encryption key must be at least %d bytes long", minEncryptionKeyLength)
|
return nil, fmt.Errorf("encryption key must be at least %d bytes long", minEncryptionKeyLength)
|
||||||
}
|
}
|
||||||
@@ -80,13 +81,19 @@ func NewSessionManager(encryptionKey string, forceHTTPS bool, cookieDomain strin
|
|||||||
cookiePrefix = "_oidc_raczylo_"
|
cookiePrefix = "_oidc_raczylo_"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set default session max age if not provided (24 hours for backward compatibility)
|
||||||
|
if sessionMaxAge == 0 {
|
||||||
|
sessionMaxAge = absoluteSessionTimeout
|
||||||
|
}
|
||||||
|
|
||||||
sm := &SessionManager{
|
sm := &SessionManager{
|
||||||
store: sessions.NewCookieStore([]byte(encryptionKey)),
|
store: sessions.NewCookieStore([]byte(encryptionKey)),
|
||||||
forceHTTPS: forceHTTPS,
|
forceHTTPS: forceHTTPS,
|
||||||
cookieDomain: cookieDomain,
|
cookieDomain: cookieDomain,
|
||||||
cookiePrefix: cookiePrefix,
|
cookiePrefix: cookiePrefix,
|
||||||
logger: logger,
|
sessionMaxAge: sessionMaxAge,
|
||||||
chunkManager: chunkManager,
|
logger: logger,
|
||||||
|
chunkManager: chunkManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
sm.sessionPool.New = func() interface{} {
|
sm.sessionPool.New = func() interface{} {
|
||||||
@@ -322,7 +329,7 @@ func (sm *SessionManager) getSessionOptions(isSecure bool) *sessions.Options {
|
|||||||
return &sessions.Options{
|
return &sessions.Options{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Domain: sm.cookieDomain,
|
Domain: sm.cookieDomain,
|
||||||
MaxAge: int(absoluteSessionTimeout.Seconds()),
|
MaxAge: int(sm.sessionMaxAge.Seconds()),
|
||||||
Secure: isSecure,
|
Secure: isSecure,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
SameSite: http.SameSiteLaxMode,
|
SameSite: http.SameSiteLaxMode,
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ func TestSessionManagerCreation(t *testing.T) {
|
|||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
|
|
||||||
sm, err := NewSessionManager(tt.encryptionKey, false, "", "", logger, chunkManager)
|
sm, err := NewSessionManager(tt.encryptionKey, false, "", "", 0, logger, chunkManager)
|
||||||
|
|
||||||
if tt.expectError {
|
if tt.expectError {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -200,7 +200,7 @@ func TestSessionManagerCreation(t *testing.T) {
|
|||||||
func TestSessionManagerPoolBehavior(t *testing.T) {
|
func TestSessionManagerPoolBehavior(t *testing.T) {
|
||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger, chunkManager)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -291,7 +291,7 @@ func TestSessionManagerPoolBehavior(t *testing.T) {
|
|||||||
func TestSessionManagerErrorHandling(t *testing.T) {
|
func TestSessionManagerErrorHandling(t *testing.T) {
|
||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger, chunkManager)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -390,7 +390,7 @@ func TestSessionManagerCleanup(t *testing.T) {
|
|||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
mockChunkManager := &MockChunkManager{}
|
mockChunkManager := &MockChunkManager{}
|
||||||
|
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger, mockChunkManager)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger, mockChunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -458,7 +458,7 @@ func TestSessionManagerHTTPSBehavior(t *testing.T) {
|
|||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
|
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
tt.forceHTTPS, "", "", logger, chunkManager)
|
tt.forceHTTPS, "", "", 0, logger, chunkManager)
|
||||||
|
|
||||||
if tt.expectError {
|
if tt.expectError {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -520,7 +520,7 @@ func TestSessionManagerCookieDomain(t *testing.T) {
|
|||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
|
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
false, tt.cookieDomain, "", logger, chunkManager)
|
false, tt.cookieDomain, "", 0, logger, chunkManager)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error for %s: %v", tt.description, err)
|
t.Errorf("Unexpected error for %s: %v", tt.description, err)
|
||||||
@@ -549,7 +549,7 @@ func BenchmarkSessionManagerCreation(b *testing.B) {
|
|||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
sm, err := NewSessionManager(encryptionKey, false, "", "", logger, chunkManager)
|
sm, err := NewSessionManager(encryptionKey, false, "", "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Failed to create session manager: %v", err)
|
b.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -561,7 +561,7 @@ func BenchmarkSessionManagerCreation(b *testing.B) {
|
|||||||
func BenchmarkSessionManagerGetSession(b *testing.B) {
|
func BenchmarkSessionManagerGetSession(b *testing.B) {
|
||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger, chunkManager)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Failed to create session manager: %v", err)
|
b.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -599,7 +599,7 @@ func minInt(a, b int) int {
|
|||||||
func TestValidateSessionHealth(t *testing.T) {
|
func TestValidateSessionHealth(t *testing.T) {
|
||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger, chunkManager)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -660,7 +660,7 @@ func TestValidateSessionHealth(t *testing.T) {
|
|||||||
func TestValidateTokenFormat(t *testing.T) {
|
func TestValidateTokenFormat(t *testing.T) {
|
||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger, chunkManager)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -727,7 +727,7 @@ func TestValidateTokenFormat(t *testing.T) {
|
|||||||
func TestDetectSessionTampering(t *testing.T) {
|
func TestDetectSessionTampering(t *testing.T) {
|
||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger, chunkManager)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -812,7 +812,7 @@ func TestGetSessionMetrics(t *testing.T) {
|
|||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
tt.forceHTTPS, tt.cookieDomain, "", logger, chunkManager)
|
tt.forceHTTPS, tt.cookieDomain, "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -898,7 +898,7 @@ func TestShouldUseSecureCookies(t *testing.T) {
|
|||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
tt.forceHTTPS, "", "", logger, chunkManager)
|
tt.forceHTTPS, "", "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -940,7 +940,7 @@ func TestGetSessionOptions(t *testing.T) {
|
|||||||
logger := &MockLogger{}
|
logger := &MockLogger{}
|
||||||
chunkManager := &MockChunkManager{}
|
chunkManager := &MockChunkManager{}
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
false, tt.cookieDomain, "", logger, chunkManager)
|
false, tt.cookieDomain, "", 0, logger, chunkManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
// TestSetCodeVerifier_NoChange tests the branch where the code verifier value doesn't change
|
// TestSetCodeVerifier_NoChange tests the branch where the code verifier value doesn't change
|
||||||
func TestSetCodeVerifier_NoChange(t *testing.T) {
|
func TestSetCodeVerifier_NoChange(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ func TestSetCodeVerifier_NoChange(t *testing.T) {
|
|||||||
// TestClearTokenChunks_EmptyChunks tests the branch where the chunks map is empty
|
// TestClearTokenChunks_EmptyChunks tests the branch where the chunks map is empty
|
||||||
func TestClearTokenChunks_EmptyChunks(t *testing.T) {
|
func TestClearTokenChunks_EmptyChunks(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ func TestClearTokenChunks_EmptyChunks(t *testing.T) {
|
|||||||
// TestClearTokenChunks_WithSessions tests the branch where the chunks map contains actual sessions
|
// TestClearTokenChunks_WithSessions tests the branch where the chunks map contains actual sessions
|
||||||
func TestClearTokenChunks_WithSessions(t *testing.T) {
|
func TestClearTokenChunks_WithSessions(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-16
@@ -84,7 +84,7 @@ func TestSessionPoolMemoryLeak(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ func TestSessionPoolMemoryLeak(t *testing.T) {
|
|||||||
session.ReturnToPool()
|
session.ReturnToPool()
|
||||||
|
|
||||||
case "Error path in GetSession":
|
case "Error path in GetSession":
|
||||||
badSM, _ := NewSessionManager("different0123456789abcdef0123456789abcdef0123456789", false, "", "", logger)
|
badSM, _ := NewSessionManager("different0123456789abcdef0123456789abcdef0123456789", false, "", "", 0, logger)
|
||||||
_, err = badSM.GetSession(req)
|
_, err = badSM.GetSession(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Log("Note: Expected error when using mismatched encryption keys")
|
t.Log("Note: Expected error when using mismatched encryption keys")
|
||||||
@@ -172,7 +172,7 @@ func TestSessionErrorHandling(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -226,7 +226,7 @@ func TestSessionClearAlwaysReturnsToPool(t *testing.T) {
|
|||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
Operation: func() error {
|
Operation: func() error {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create session manager: %w", err)
|
return fmt.Errorf("failed to create session manager: %w", err)
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ func TestSessionClearAlwaysReturnsToPool(t *testing.T) {
|
|||||||
// Additional verification test
|
// Additional verification test
|
||||||
t.Run("Verify pool still works after errors", func(t *testing.T) {
|
t.Run("Verify pool still works after errors", func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -324,7 +324,7 @@ func TestSessionObjectTracking(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -574,7 +574,7 @@ func TestTokenChunkingIntegrity(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -681,7 +681,7 @@ func TestTokenChunkingCorruptionResistance(t *testing.T) {
|
|||||||
for _, test := range corruptionTests {
|
for _, test := range corruptionTests {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -772,7 +772,7 @@ func TestTokenSizeLimits(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -837,7 +837,7 @@ func TestConcurrentTokenOperations(t *testing.T) {
|
|||||||
Timeout: 60 * time.Second,
|
Timeout: 60 * time.Second,
|
||||||
Operation: func() error {
|
Operation: func() error {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create session manager: %w", err)
|
return fmt.Errorf("failed to create session manager: %w", err)
|
||||||
}
|
}
|
||||||
@@ -925,7 +925,7 @@ func TestSessionValidationAndCleanup(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1010,7 +1010,7 @@ func TestLargeIDTokenChunking(t *testing.T) {
|
|||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1115,7 +1115,7 @@ func BenchmarkSessionOperations(b *testing.B) {
|
|||||||
perfHelper := NewPerformanceTestHelper()
|
perfHelper := NewPerformanceTestHelper()
|
||||||
|
|
||||||
logger := NewLogger("error") // Reduce logging for benchmarks
|
logger := NewLogger("error") // Reduce logging for benchmarks
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("Failed to create session manager: %v", err)
|
b.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1256,7 +1256,7 @@ func TestSessionStatePreservationWithExpiredTokens(t *testing.T) {
|
|||||||
t.Log("Testing session state preservation with expired tokens - this test demonstrates BROKEN BEHAVIOR")
|
t.Log("Testing session state preservation with expired tokens - this test demonstrates BROKEN BEHAVIOR")
|
||||||
|
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("test-session-key-32-bytes-long-12345", false, "", "", logger)
|
sm, err := NewSessionManager("test-session-key-32-bytes-long-12345", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1452,7 +1452,7 @@ func TestSessionExpiryVsTokenExpiry(t *testing.T) {
|
|||||||
t.Log("Testing session expiry vs token expiry distinction - validating proper session and token lifetime management")
|
t.Log("Testing session expiry vs token expiry distinction - validating proper session and token lifetime management")
|
||||||
|
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("session-vs-token-test-key-32-bytes", false, "", "", logger)
|
sm, err := NewSessionManager("session-vs-token-test-key-32-bytes", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1591,7 +1591,7 @@ func TestSessionCleanupOnTokenExpiry(t *testing.T) {
|
|||||||
t.Log("Testing session cleanup on token expiry - validating proper session data management")
|
t.Log("Testing session cleanup on token expiry - validating proper session data management")
|
||||||
|
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("cleanup-test-key-32-bytes-long-123", false, "", "", logger)
|
sm, err := NewSessionManager("cleanup-test-key-32-bytes-long-123", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -30,7 +30,8 @@ type Config struct {
|
|||||||
HTTPClient *http.Client `json:"-"`
|
HTTPClient *http.Client `json:"-"`
|
||||||
OIDCEndSessionURL string `json:"oidcEndSessionURL"`
|
OIDCEndSessionURL string `json:"oidcEndSessionURL"`
|
||||||
CookieDomain string `json:"cookieDomain"`
|
CookieDomain string `json:"cookieDomain"`
|
||||||
CookiePrefix string `json:"cookiePrefix"` // Prefix for session cookie names (default: "_oidc_raczylo_")
|
CookiePrefix string `json:"cookiePrefix"` // Prefix for session cookie names (default: "_oidc_raczylo_")
|
||||||
|
SessionMaxAge int `json:"sessionMaxAge"` // Maximum session age in seconds (default: 86400 = 24 hours)
|
||||||
CallbackURL string `json:"callbackURL"`
|
CallbackURL string `json:"callbackURL"`
|
||||||
LogoutURL string `json:"logoutURL"`
|
LogoutURL string `json:"logoutURL"`
|
||||||
ClientID string `json:"clientID"`
|
ClientID string `json:"clientID"`
|
||||||
|
|||||||
@@ -280,6 +280,7 @@ func (tf *TestFramework) CreateAuthenticatedRequest(method, path string) (*http.
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
0,
|
||||||
tf.oidc.logger,
|
tf.oidc.logger,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -325,6 +326,7 @@ func (tf *TestFramework) CreateCallbackRequest() *http.Request {
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
0,
|
||||||
tf.oidc.logger,
|
tf.oidc.logger,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ func createMockJWT(t *testing.T, sub, email string) string {
|
|||||||
func createTestSession() *SessionData {
|
func createTestSession() *SessionData {
|
||||||
// Create a minimal session manager for testing
|
// Create a minimal session manager for testing
|
||||||
logger := newNoOpLogger()
|
logger := newNoOpLogger()
|
||||||
sessionManager, _ := NewSessionManager("test-encryption-key-32-characters", false, "", "", logger)
|
sessionManager, _ := NewSessionManager("test-encryption-key-32-characters", false, "", "", 0, logger)
|
||||||
|
|
||||||
// Create a test request
|
// Create a test request
|
||||||
req := httptest.NewRequest("GET", "/", nil)
|
req := httptest.NewRequest("GET", "/", nil)
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ func TestTokenTypes(t *testing.T) {
|
|||||||
func TestTokenCorruption(t *testing.T) {
|
func TestTokenCorruption(t *testing.T) {
|
||||||
t.Run("TokenCorruptionScenario", func(t *testing.T) {
|
t.Run("TokenCorruptionScenario", func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -291,7 +291,7 @@ func TestTokenCorruption(t *testing.T) {
|
|||||||
func TestTokenResilience(t *testing.T) {
|
func TestTokenResilience(t *testing.T) {
|
||||||
t.Run("ConcurrentTokenAccess", func(t *testing.T) {
|
t.Run("ConcurrentTokenAccess", func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -337,7 +337,7 @@ func TestTokenResilience(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("TokenSizeHandling", func(t *testing.T) {
|
t.Run("TokenSizeHandling", func(t *testing.T) {
|
||||||
logger := NewLogger("debug")
|
logger := NewLogger("debug")
|
||||||
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", logger)
|
sm, err := NewSessionManager("0123456789abcdef0123456789abcdef0123456789abcdef", false, "", "", 0, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create session manager: %v", err)
|
t.Fatalf("Failed to create session manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user