mirror of
https://github.com/goauthentik/authentik
synced 2026-04-27 09:57:31 +02:00
* proxyv2/filesystemstore: add persistent filesystem store to implement a session cleanup job * proxyv2: add session cleanup for filesystem session store
147 lines
3.6 KiB
Go
147 lines
3.6 KiB
Go
package filesystemstore
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func createTempSessionFile(t *testing.T, dir string, modTime time.Time) string {
|
|
t.Helper()
|
|
path := filepath.Join(dir, "session_test")
|
|
err := os.WriteFile(path, []byte("session data"), 0600)
|
|
require.NoError(t, err)
|
|
err = os.Chtimes(path, modTime, modTime)
|
|
require.NoError(t, err)
|
|
return path
|
|
}
|
|
|
|
func TestNewStore_PathNotExist(t *testing.T) {
|
|
_, err := NewStore("/invalid_path")
|
|
assert.ErrorIs(t, err, ErrSessionStorePathNotExist)
|
|
}
|
|
|
|
func TestNewStore_PathNotWritable(t *testing.T) {
|
|
storePath := path.Join(os.TempDir(), "test")
|
|
err := os.Mkdir(storePath, 0400)
|
|
require.NoError(t, err)
|
|
|
|
_, err = NewStore(storePath)
|
|
assert.ErrorIs(t, err, ErrSessionStoreNoPermission)
|
|
|
|
_ = os.RemoveAll(storePath)
|
|
}
|
|
|
|
func TestNewStore(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
store, err := NewStore(tmpDir)
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, store)
|
|
}
|
|
|
|
func TestSessionCleanup_RemovesExpired(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
store, err := NewStore(tmpDir)
|
|
require.NoError(t, err)
|
|
store.Options.MaxAge = 1 // 1 second
|
|
|
|
// Create an expired session file
|
|
oldTime := time.Now().Add(-10 * time.Second)
|
|
createTempSessionFile(t, tmpDir, oldTime)
|
|
|
|
ctx := context.Background()
|
|
err = store.SessionCleanup(ctx)
|
|
assert.NoError(t, err)
|
|
|
|
// File should be deleted
|
|
files, _ := os.ReadDir(tmpDir)
|
|
assert.Empty(t, files)
|
|
}
|
|
|
|
func TestSessionCleanup_PreservesValid(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
store, err := NewStore(tmpDir)
|
|
require.NoError(t, err)
|
|
store.Options.MaxAge = 3600 // 1 hour
|
|
|
|
// Create a valid (non-expired) session file
|
|
modTime := time.Now().Add(-10 * time.Second)
|
|
createTempSessionFile(t, tmpDir, modTime)
|
|
|
|
ctx := context.Background()
|
|
err = store.SessionCleanup(ctx)
|
|
assert.NoError(t, err)
|
|
|
|
// File should still exist
|
|
files, _ := os.ReadDir(tmpDir)
|
|
assert.Len(t, files, 1)
|
|
}
|
|
|
|
func TestSessionCleanup_ContextCancel(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
store, err := NewStore(tmpDir)
|
|
require.NoError(t, err)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel() // cancel immediately
|
|
|
|
err = store.SessionCleanup(ctx)
|
|
assert.ErrorIs(t, err, context.Canceled)
|
|
}
|
|
|
|
func TestSessionCleanup_AlreadyRunning(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
store, err := NewStore(tmpDir)
|
|
require.NoError(t, err)
|
|
|
|
// Manually acquire the lock before calling SessionCleanup
|
|
lockPath := path.Join(tmpDir, SessionCleanupLockFileName)
|
|
lockFile, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0600)
|
|
require.NoError(t, err, "failed to create lock file")
|
|
|
|
err = syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
|
|
require.NoError(t, err, "failed to acquire lock for test")
|
|
|
|
// Run SessionCleanup while lock is held
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
defer cancel()
|
|
|
|
err = store.SessionCleanup(ctx)
|
|
assert.ErrorIs(t, err, ErrSessionCleanupAlreadyRunning)
|
|
|
|
// Unlock and clean up
|
|
_ = syscall.Flock(int(lockFile.Fd()), syscall.LOCK_UN)
|
|
_ = lockFile.Close()
|
|
_ = os.Remove(lockPath)
|
|
}
|
|
|
|
func TestPersistentStore_ReusesStore(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
store1, err := GetPersistentStore(tmpDir)
|
|
require.NoError(t, err)
|
|
assert.NotNil(t, store1)
|
|
|
|
store2, err := GetPersistentStore(tmpDir)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, store1, store2)
|
|
|
|
StopPersistentStore()
|
|
}
|
|
|
|
func TestStopPersistentStore(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
_, err := GetPersistentStore(tmpDir)
|
|
require.NoError(t, err)
|
|
StopPersistentStore()
|
|
|
|
// call again should not panic
|
|
StopPersistentStore()
|
|
}
|