Add Session-Based Web UI Authentication with Security Hardening - closes #815#819
Add Session-Based Web UI Authentication with Security Hardening - closes #815#819viktormohl wants to merge 2 commits intogessnerfl:mainfrom
Conversation
…nerfl#815) - Implement server-side session authentication with HttpOnly cookies - Add configurable session timeout (FAKESMTP_WEBAPP_SESSION_TIMEOUT_MINUTES) - Enable CSRF protection for API requests - Add CSP headers on UI shell routes only - Restructure static assets under /assets/ with reduced public surface - Implement authenticated SSE with heartbeats, connection health indicator, Virtual Threads for high-performance delivery, and exponential backoff - Expose session metadata via /api/meta-data for UI consumption - Add SessionTimeoutManager with inactivity tracking - Update build process to include assets in bootRun/test tasks - Add configurable rate limiting for login attempts - Add configurable support for concurrent sessions
c0109fb to
c729541
Compare
src/main/java/de/gessnerfl/fakesmtp/config/AuthorizationExceptionFilter.java
Dismissed
Show dismissed
Hide dismissed
src/main/java/de/gessnerfl/fakesmtp/config/CustomAuthenticationEntryPoint.java
Dismissed
Show dismissed
Hide dismissed
src/main/java/de/gessnerfl/fakesmtp/config/InMemoryRateLimiter.java
Dismissed
Show dismissed
Hide dismissed
src/main/java/de/gessnerfl/fakesmtp/config/RateLimitingFilter.java
Dismissed
Show dismissed
Hide dismissed
src/main/java/de/gessnerfl/fakesmtp/config/RateLimitingFilter.java
Dismissed
Show dismissed
Hide dismissed
src/main/java/de/gessnerfl/fakesmtp/config/SecurityExceptionHandler.java
Dismissed
Show dismissed
Hide dismissed
gessnerfl
left a comment
There was a problem hiding this comment.
@viktormohl The change LGTM. However it seems there are failing tests. Can you please double check?
…tachment validation
|
Thanks for the note. I double-checked locally. Root cause was a flaky assertion using a fixed I also reran |
Pull Request: Add Session-Based Web UI Authentication with Security Hardening
Fixes
/, preventing the login form from rendering when authentication was enabledSummary
This PR implements comprehensive Web UI authentication with server-side session management, CSRF protection, rate limiting, and real-time notifications via SSE. The authentication system supports both enabled and disabled modes, ensuring backward compatibility for existing deployments.
Key Changes
🔐 Authentication & Session Management
Backend:
FAKESMTP_WEBAPP_SESSION_TIMEOUT_MINUTES(default: 10 minutes, max: 24 hours)FAKESMTP_WEBAPP_AUTHENTICATION_CONCURRENT_SESSIONS(default: 1)changeSessionId()on login)SpaCsrfTokenRequestHandlerFrontend:
API:
POST /api/auth/login,POST /api/auth/logout,GET /api/auth/statusGET /api/meta-data) exposes auth status and session timeout🛡️ Security Hardening
CSRF Protection:
XSRF-TOKENcookie andX-XSRF-TOKENheaderRate Limiting:
FAKESMTP_WEBAPP_RATE_LIMITING_ENABLED(default: true)FAKESMTP_WEBAPP_RATE_LIMITING_MAX_ATTEMPTS(default: 5, max: 100)FAKESMTP_WEBAPP_RATE_LIMITING_WINDOW_MINUTES(default: 1, max: 60)Retry-AfterandX-RateLimit-RemainingheadersX-Forwarded-ForandX-Real-IPfor proxy environmentsSecurity Headers:
/,/emails/**)X-Content-Type-Options: nosniffgloballyReferrer-Policy: strict-origin-when-cross-origingloballyX-Frame-Options: sameoriginfor clickjacking protectionStatic Assets:
/assets/**(previously root level)copyStaticAssetstask switched toSyncto prevent stale assets📡 Server-Sent Events (SSE) Enhancements
Performance:
Reliability:
Authentication:
AuthenticatedEventSourceusing Fetch API withcredentials: "same-origin"🧪 Test Coverage
New Integration Tests:
WebappAuthenticationSecurityIntegrationTest(327 lines)WebappAuthenticationDisabledIntegrationTest(156 lines)RateLimitingFilterIntegrationTest(288 lines)Updated Tests:
CustomAuthenticationEntryPointTest- SPA rendering validationMetaDataControllerTest- Session timeout and auth statusEmailSseEmitterServiceTest- Virtual Thread delivery and heartbeats📁 Files Changed
Backend (Java):
Frontend (React/TypeScript):
Configuration:
Tests:
Documentation:
Breaking Changes
None. The implementation is fully backward compatible:
FAKESMTP_WEBAPP_AUTH_USERNAMEandFAKESMTP_WEBAPP_AUTH_PASSWORDare not set, authentication is disabled and all endpoints work as before/assets/**- existing deployments continue to work as the Spring Boot resource handler serves them correctlyMigration Guide
For Existing Deployments (No Auth)
No action required. The application will continue to work without authentication if credentials are not configured.
For New Auth-Enabled Deployments
Set environment variables:
Access the UI and login with the configured credentials
For API clients: Obtain CSRF token from
/api/meta-dataand include in state-changing requestsFor Development/Testing (Multiple Concurrent Sessions)
To allow multiple browsers/devices to stay logged in simultaneously with the same credentials:
FAKESMTP_WEBAPP_AUTH_USERNAME=admin FAKESMTP_WEBAPP_AUTH_PASSWORD=securepassword FAKESMTP_WEBAPP_AUTHENTICATION_CONCURRENT_SESSIONS=-1 # Unlimited sessionsOr set a specific limit:
FAKESMTP_WEBAPP_AUTHENTICATION_CONCURRENT_SESSIONS=5 # Max 5 concurrent sessionsConfiguration Reference
Environment Variables
FAKESMTP_WEBAPP_AUTH_USERNAMEFAKESMTP_WEBAPP_AUTH_PASSWORDFAKESMTP_WEBAPP_SESSION_TIMEOUT_MINUTESFAKESMTP_WEBAPP_AUTHENTICATION_CONCURRENT_SESSIONSFAKESMTP_WEBAPP_SSE_HEARTBEAT_INTERVAL_SECONDSFAKESMTP_WEBAPP_SSE_EVENT_SEND_TIMEOUT_SECONDSFAKESMTP_WEBAPP_RATE_LIMITING_ENABLEDFAKESMTP_WEBAPP_RATE_LIMITING_MAX_ATTEMPTSFAKESMTP_WEBAPP_RATE_LIMITING_WINDOW_MINUTESFAKESMTP_WEBAPP_RATE_LIMITING_WHITELIST_LOCALHOSTAuthentication Modes
Mode 1: Authentication Disabled (Default)
Mode 2: Authentication Enabled
/,/emails/**) loads without auth to render login form/api/meta-dataaccessible to check auth status/api/**endpoints require authenticationTesting
Manual Testing Checklist
Without Authentication:
/without login/api/emailswithout 401With Authentication:
/shows login form/api/emailsrequires authentication-1: multiple sessions allowed)Automated Tests
Run all tests:
./gradlew testRun specific test classes:
Performance Considerations
Security Considerations
Additional Notes
/,/emails/**) is intentionally public to allow the React app to load and render its own login form/api/**endpointsXSRF-TOKENcookie is not HttpOnly (must be accessible to JavaScript for SPA), but is protected by SameSite=LaxChecklist
./gradlew test)npm run buildin webapp/)