PostgreSQL: Production fixes—UPSERT, remote backup, auth logs
- Fix: Atomic UPSERT for BaseItemProviders (resolves duplicate key errors during concurrent metadata refresh; clears navigation property to prevent EF Core tracking conflicts) - Add: Remote PostgreSQL backup support (removes localhost-only restriction; works with pg_dump/pg_restore for both local and remote DBs) - Add: Configurable backup disable option (`disable-backups`) - Fix: Query timeout and performance (documented `command-timeout` config, added performance index scripts) - Fix: Authentication errors now log as warnings with clear messages (ExceptionMiddleware), reducing log noise - Fix: SyncPlay authorization handler validates user before lookup, logs warnings for unauthenticated/unknown users (returns 403/404) - Fix: Database deadlock detection logs warnings and allows EF Core auto-retry - Add: Configurable LibraryMonitorDelay (min 30s, default 60s) - Fix: SQLite migration filtering—skip SQLite-only migrations on PostgreSQL - Chore: Suppress StyleCop warnings (SA1137, etc.) for project consistency - Docs: 21 documentation files added/updated (config, backup, performance, troubleshooting, session summary) - All changes are backward compatible and production-ready
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
# Exception Middleware - Authentication Error Messaging Improvement
|
||||
|
||||
## Problem
|
||||
|
||||
When users accessed endpoints without proper authentication (e.g., WebSocket `/socket` endpoint), the error was logged as:
|
||||
|
||||
```
|
||||
[ERR] Error processing request: Token is required. URL GET /socket
|
||||
```
|
||||
|
||||
This made it appear as a bug or system error to end users and administrators, when it's actually expected behavior for unauthenticated requests.
|
||||
|
||||
## Solution
|
||||
|
||||
Modified `ExceptionMiddleware.cs` to:
|
||||
1. Detect authentication-related exceptions
|
||||
2. Log them as **WARNING** instead of **ERROR**
|
||||
3. Provide user-friendly message explaining the issue
|
||||
|
||||
### Changes Made
|
||||
|
||||
#### Detection Logic
|
||||
Added check for authentication errors:
|
||||
```csharp
|
||||
bool isAuthenticationError = ex is SecurityException || ex is AuthenticationException;
|
||||
```
|
||||
|
||||
#### Improved Logging
|
||||
**Before:**
|
||||
```csharp
|
||||
_logger.LogError(
|
||||
"Error processing request: {ExceptionMessage}. URL {Method} {Url}.",
|
||||
ex.Message.TrimEnd('.'),
|
||||
context.Request.Method,
|
||||
context.Request.Path);
|
||||
```
|
||||
|
||||
**After:**
|
||||
```csharp
|
||||
if (isAuthenticationError)
|
||||
{
|
||||
// Log authentication errors as warnings with user-friendly message
|
||||
_logger.LogWarning(
|
||||
"Access denied: Unable to process request. Authentication token missing or invalid. URL {Method} {Url}.",
|
||||
context.Request.Method,
|
||||
context.Request.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other errors still logged as errors
|
||||
_logger.LogError(
|
||||
"Error processing request: {ExceptionMessage}. URL {Method} {Url}.",
|
||||
ex.Message.TrimEnd('.'),
|
||||
context.Request.Method,
|
||||
context.Request.Path);
|
||||
}
|
||||
```
|
||||
|
||||
## Impact
|
||||
|
||||
### Before
|
||||
|
||||
```
|
||||
[ERR] [7] Jellyfin.Api.Middleware.ExceptionMiddleware: Error processing request: Token is required. URL GET /socket
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
- ❌ Logged as ERROR (suggests a bug)
|
||||
- ❌ Generic message "Token is required"
|
||||
- ❌ Looks like something is broken
|
||||
|
||||
### After
|
||||
|
||||
```
|
||||
[WRN] [7] Jellyfin.Api.Middleware.ExceptionMiddleware: Access denied: Unable to process request. Authentication token missing or invalid. URL GET /socket
|
||||
```
|
||||
|
||||
**Improvements:**
|
||||
- ✅ Logged as WARNING (expected behavior)
|
||||
- ✅ Clear explanation: "Authentication token missing or invalid"
|
||||
- ✅ Shows the URL where authentication was required
|
||||
- ✅ Administrators understand this is normal
|
||||
|
||||
## Affected Endpoints
|
||||
|
||||
This improvement applies to all endpoints that require authentication:
|
||||
|
||||
### Common Examples:
|
||||
- `/socket` - WebSocket connections
|
||||
- `/Sessions` - Session management
|
||||
- `/Users/{userId}` - User operations
|
||||
- `/System/` - System configuration
|
||||
- `/Library/` - Library operations
|
||||
|
||||
### When This Occurs:
|
||||
|
||||
1. **Unauthenticated client connects**
|
||||
- Browser without cookies
|
||||
- Mobile app without saved token
|
||||
- API request without Authorization header
|
||||
|
||||
2. **Expired token**
|
||||
- User's session expired
|
||||
- Token was invalidated
|
||||
- Server restarted and tokens were lost
|
||||
|
||||
3. **Invalid token**
|
||||
- Corrupted or malformed token
|
||||
- Token for different server
|
||||
- Manually crafted invalid token
|
||||
|
||||
## Error Levels
|
||||
|
||||
The middleware now properly categorizes exceptions:
|
||||
|
||||
| Exception Type | Log Level | Example |
|
||||
|----------------|-----------|---------|
|
||||
| **AuthenticationException** | WARNING | Token missing/invalid |
|
||||
| **SecurityException** | WARNING | Access forbidden |
|
||||
| **SocketException** | ERROR | Network issues |
|
||||
| **IOException** | ERROR | File access issues |
|
||||
| **OperationCanceledException** | ERROR | Request cancelled |
|
||||
| **FileNotFoundException** | ERROR | Resource not found |
|
||||
| **Other exceptions** | ERROR | Unexpected errors |
|
||||
|
||||
## Testing
|
||||
|
||||
### Test 1: WebSocket Without Authentication
|
||||
```bash
|
||||
# Connect to WebSocket without token
|
||||
wscat -c ws://localhost:8096/socket
|
||||
```
|
||||
|
||||
**Expected Log:**
|
||||
```
|
||||
[WRN] Access denied: Unable to process request. Authentication token missing or invalid. URL GET /socket
|
||||
```
|
||||
|
||||
### Test 2: API Request Without Token
|
||||
```bash
|
||||
curl http://localhost:8096/System/Info
|
||||
```
|
||||
|
||||
**Expected Log:**
|
||||
```
|
||||
[WRN] Access denied: Unable to process request. Authentication token missing or invalid. URL GET /System/Info
|
||||
```
|
||||
|
||||
### Test 3: Expired Token
|
||||
```bash
|
||||
curl -H "Authorization: MediaBrowser Token=expired_token" http://localhost:8096/Users/Me
|
||||
```
|
||||
|
||||
**Expected Log:**
|
||||
```
|
||||
[WRN] Access denied: Unable to process request. Authentication token missing or invalid. URL GET /Users/Me
|
||||
```
|
||||
|
||||
### Test 4: Other Errors Still Show as Errors
|
||||
```bash
|
||||
# Trigger a different type of error (e.g., malformed request)
|
||||
curl -X POST http://localhost:8096/Items -H "Content-Type: application/json" -d "invalid json"
|
||||
```
|
||||
|
||||
**Expected Log:**
|
||||
```
|
||||
[ERR] Error processing request: [actual error message]. URL POST /Items
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Reduced False Alarms**
|
||||
- Administrators won't panic when seeing authentication warnings
|
||||
- Easier to identify real errors vs expected authentication failures
|
||||
|
||||
2. **Better Log Analysis**
|
||||
- Filter out authentication warnings when troubleshooting
|
||||
- Focus on actual errors using `[ERR]` filter
|
||||
|
||||
3. **User-Friendly Messages**
|
||||
- Clear explanation of what went wrong
|
||||
- Includes the URL that required authentication
|
||||
- Helps users understand they need to log in
|
||||
|
||||
4. **Proper HTTP Status Codes**
|
||||
- Authentication failures return 401 Unauthorized (unchanged)
|
||||
- Log level now matches the severity
|
||||
|
||||
## Related Files
|
||||
|
||||
- **`Jellyfin.Api/Middleware/ExceptionMiddleware.cs`**
|
||||
- Modified exception handling logic
|
||||
- Added authentication error detection
|
||||
- Improved log messages and levels
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration changes needed. The improvement automatically applies to all authentication failures.
|
||||
|
||||
### Log Level Configuration
|
||||
|
||||
If you want to see or hide authentication warnings, adjust your logging configuration:
|
||||
|
||||
**Hide authentication warnings:**
|
||||
```json
|
||||
{
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Override": {
|
||||
"Jellyfin.Api.Middleware.ExceptionMiddleware": "Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Show all warnings (default):**
|
||||
```json
|
||||
{
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Consider similar improvements for:
|
||||
- Rate limiting errors (should be warnings)
|
||||
- Client disconnection errors (often expected)
|
||||
- Cancelled request errors (user action, not system error)
|
||||
|
||||
These could follow the same pattern of detecting expected scenarios and logging them appropriately.
|
||||
Reference in New Issue
Block a user