Record auth audits and surface them in Activity, poll sidebar counts without resetting idle, and add a profile logout path plus theme red/green/blue tokens so failure badges render.
175 lines
5.2 KiB
Go
175 lines
5.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"codeberg.org/SquidSE/ClusterCanvas/service/internal/settings"
|
|
)
|
|
|
|
func TestLookupValidSessionReturnsIdle(t *testing.T) {
|
|
configDir := t.TempDir()
|
|
key := testSessionKey()
|
|
manager := NewSessionManager(configDir, key)
|
|
security := settings.DefaultSecuritySettings()
|
|
security.IdleTimeoutMinutes = 5
|
|
|
|
createRec := httptest.NewRecorder()
|
|
record, err := manager.CreateSession(createRec, "user-1", security)
|
|
if err != nil {
|
|
t.Fatalf("CreateSession: %v", err)
|
|
}
|
|
|
|
store, err := settings.LoadSessions(configDir, key)
|
|
if err != nil {
|
|
t.Fatalf("LoadSessions: %v", err)
|
|
}
|
|
if len(store.Sessions) != 1 {
|
|
t.Fatalf("expected 1 session, got %d", len(store.Sessions))
|
|
}
|
|
store.Sessions[0].LastSeenAt = time.Now().UTC().Add(-6 * time.Minute)
|
|
if err := settings.SaveSessions(configDir, store, key); err != nil {
|
|
t.Fatalf("SaveSessions: %v", err)
|
|
}
|
|
|
|
request := httptest.NewRequest(http.MethodGet, "/api/v1/status", nil)
|
|
request.AddCookie(&http.Cookie{Name: SessionCookieName, Value: record.ID})
|
|
lookupRec := httptest.NewRecorder()
|
|
|
|
_, err = manager.LookupValidSession(lookupRec, request, security, true)
|
|
if !errors.Is(err, ErrSessionIdle) {
|
|
t.Fatalf("expected ErrSessionIdle, got %v", err)
|
|
}
|
|
|
|
store, err = settings.LoadSessionsOrEmpty(configDir, key)
|
|
if err != nil {
|
|
t.Fatalf("LoadSessionsOrEmpty: %v", err)
|
|
}
|
|
if len(store.Sessions) != 0 {
|
|
t.Fatalf("expected idle session removed, got %#v", store.Sessions)
|
|
}
|
|
}
|
|
|
|
func TestLookupValidSessionMissingCookie(t *testing.T) {
|
|
configDir := t.TempDir()
|
|
manager := NewSessionManager(configDir, testSessionKey())
|
|
security := settings.DefaultSecuritySettings()
|
|
|
|
request := httptest.NewRequest(http.MethodGet, "/api/v1/status", nil)
|
|
lookupRec := httptest.NewRecorder()
|
|
|
|
_, err := manager.LookupValidSession(lookupRec, request, security, true)
|
|
if !errors.Is(err, ErrSessionNotFound) {
|
|
t.Fatalf("expected ErrSessionNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLookupValidSessionUnknownCookie(t *testing.T) {
|
|
configDir := t.TempDir()
|
|
manager := NewSessionManager(configDir, testSessionKey())
|
|
security := settings.DefaultSecuritySettings()
|
|
|
|
request := httptest.NewRequest(http.MethodGet, "/api/v1/status", nil)
|
|
request.AddCookie(&http.Cookie{Name: SessionCookieName, Value: "unknown-session"})
|
|
lookupRec := httptest.NewRecorder()
|
|
|
|
_, err := manager.LookupValidSession(lookupRec, request, security, true)
|
|
if !errors.Is(err, ErrSessionNotFound) {
|
|
t.Fatalf("expected ErrSessionNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLookupValidSessionWithoutTouchLeavesLastSeenAt(t *testing.T) {
|
|
configDir := t.TempDir()
|
|
key := testSessionKey()
|
|
manager := NewSessionManager(configDir, key)
|
|
security := settings.DefaultSecuritySettings()
|
|
security.IdleTimeoutMinutes = 30
|
|
|
|
createRec := httptest.NewRecorder()
|
|
record, err := manager.CreateSession(createRec, "user-1", security)
|
|
if err != nil {
|
|
t.Fatalf("CreateSession: %v", err)
|
|
}
|
|
|
|
store, err := settings.LoadSessions(configDir, key)
|
|
if err != nil {
|
|
t.Fatalf("LoadSessions: %v", err)
|
|
}
|
|
originalLastSeen := time.Now().UTC().Add(-10 * time.Minute).Truncate(time.Second)
|
|
store.Sessions[0].LastSeenAt = originalLastSeen
|
|
if err := settings.SaveSessions(configDir, store, key); err != nil {
|
|
t.Fatalf("SaveSessions: %v", err)
|
|
}
|
|
|
|
request := httptest.NewRequest(http.MethodGet, "/api/v1/status", nil)
|
|
request.AddCookie(&http.Cookie{Name: SessionCookieName, Value: record.ID})
|
|
lookupRec := httptest.NewRecorder()
|
|
|
|
got, err := manager.LookupValidSession(lookupRec, request, security, false)
|
|
if err != nil {
|
|
t.Fatalf("LookupValidSession: %v", err)
|
|
}
|
|
if got.ID != record.ID {
|
|
t.Fatalf("expected session id %q, got %q", record.ID, got.ID)
|
|
}
|
|
|
|
store, err = settings.LoadSessions(configDir, key)
|
|
if err != nil {
|
|
t.Fatalf("LoadSessions after lookup: %v", err)
|
|
}
|
|
if len(store.Sessions) != 1 {
|
|
t.Fatalf("expected 1 session, got %d", len(store.Sessions))
|
|
}
|
|
if !store.Sessions[0].LastSeenAt.Equal(originalLastSeen) {
|
|
t.Fatalf(
|
|
"expected LastSeenAt %v unchanged, got %v",
|
|
originalLastSeen,
|
|
store.Sessions[0].LastSeenAt,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestLookupValidSessionIdleWithoutTouchStillIdle(t *testing.T) {
|
|
configDir := t.TempDir()
|
|
key := testSessionKey()
|
|
manager := NewSessionManager(configDir, key)
|
|
security := settings.DefaultSecuritySettings()
|
|
security.IdleTimeoutMinutes = 5
|
|
|
|
createRec := httptest.NewRecorder()
|
|
record, err := manager.CreateSession(createRec, "user-1", security)
|
|
if err != nil {
|
|
t.Fatalf("CreateSession: %v", err)
|
|
}
|
|
|
|
store, err := settings.LoadSessions(configDir, key)
|
|
if err != nil {
|
|
t.Fatalf("LoadSessions: %v", err)
|
|
}
|
|
store.Sessions[0].LastSeenAt = time.Now().UTC().Add(-6 * time.Minute)
|
|
if err := settings.SaveSessions(configDir, store, key); err != nil {
|
|
t.Fatalf("SaveSessions: %v", err)
|
|
}
|
|
|
|
request := httptest.NewRequest(http.MethodGet, "/api/v1/status", nil)
|
|
request.AddCookie(&http.Cookie{Name: SessionCookieName, Value: record.ID})
|
|
lookupRec := httptest.NewRecorder()
|
|
|
|
_, err = manager.LookupValidSession(lookupRec, request, security, false)
|
|
if !errors.Is(err, ErrSessionIdle) {
|
|
t.Fatalf("expected ErrSessionIdle, got %v", err)
|
|
}
|
|
}
|
|
|
|
func testSessionKey() []byte {
|
|
key := make([]byte, 32)
|
|
for index := range key {
|
|
key[index] = byte(index + 3)
|
|
}
|
|
return key
|
|
}
|