c76853a442
- 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
236 lines
6.2 KiB
Markdown
236 lines
6.2 KiB
Markdown
# 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.
|