Enhanced logging & error handling for auth and pg backups

- Add detailed debug/warning logs to authentication flows (AuthService, AuthorizationContext, WebSocketManager) for better traceability of auth attempts and failures.
- Log WebSocket authentication attempts, including IP, path, and token preview.
- Introduce PostgresVersionMismatchException for pg_dump/pg_restore version mismatches; parse and log server/client versions, clean up failed backups, and provide upgrade guidance.
- Add helper for parsing version mismatch errors.
- Update using directives and minor code cleanups.
- Update .csproj.user with new publish profile path.
This commit is contained in:
2026-03-04 12:37:39 -05:00
parent 895372fe98
commit 667c3768a9
8 changed files with 197 additions and 3 deletions
@@ -4,22 +4,27 @@
#pragma warning disable CS1591
using System;
using System.Threading.Tasks;
using Jellyfin.Data;
using Jellyfin.Database.Implementations.Enums;
using MediaBrowser.Controller.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.HttpServer.Security
{
public class AuthService : IAuthService
{
private readonly IAuthorizationContext _authorizationContext;
private readonly ILogger<AuthService> _logger;
public AuthService(
IAuthorizationContext authorizationContext)
IAuthorizationContext authorizationContext,
ILogger<AuthService> logger)
{
_authorizationContext = authorizationContext;
_logger = logger;
}
public async Task<AuthorizationInfo> Authenticate(HttpRequest request)
@@ -28,19 +33,44 @@ namespace Emby.Server.Implementations.HttpServer.Security
if (!auth.HasToken)
{
_logger.LogDebug(
"Authentication failed: No token provided. Path: {Path}, Client: {Client}, Device: {Device}, DeviceId: {DeviceId}",
request.Path,
auth.Client ?? "unknown",
auth.Device ?? "unknown",
auth.DeviceId ?? "unknown");
return auth;
}
if (!auth.IsAuthenticated)
{
var tokenPreview = auth.Token?.Length > 8 ? auth.Token.Substring(0, 8) + "..." : auth.Token ?? "null";
_logger.LogDebug(
"Authentication failed: Invalid token. Path: {Path}, Client: {Client}, Device: {Device}, DeviceId: {DeviceId}, Token: {Token}",
request.Path,
auth.Client ?? "unknown",
auth.Device ?? "unknown",
auth.DeviceId ?? "unknown",
tokenPreview);
throw new SecurityException("Invalid token.");
}
if (auth.User?.HasPermission(PermissionKind.IsDisabled) ?? false)
{
_logger.LogWarning(
"Authentication failed: User account disabled. User: {User}, Path: {Path}",
auth.User.Username,
request.Path);
throw new SecurityException("User account has been disabled.");
}
_logger.LogDebug(
"Authentication successful. User: {User}, Client: {Client}, Device: {Device}, Path: {Path}",
auth.User?.Username ?? "ApiKey",
auth.Client ?? "unknown",
auth.Device ?? "unknown",
request.Path);
return auth;
}
}
@@ -40,9 +40,23 @@ namespace Emby.Server.Implementations.HttpServer
/// <inheritdoc />
public async Task WebSocketRequestHandler(HttpContext context)
{
_logger.LogDebug(
"WebSocket authentication attempt from {IP}, Path: {Path}, QueryString: {QueryString}",
context.Connection.RemoteIpAddress,
context.Request.Path,
context.Request.QueryString);
var authorizationInfo = await _authService.Authenticate(context.Request).ConfigureAwait(false);
if (!authorizationInfo.IsAuthenticated)
{
var tokenPreview = authorizationInfo.HasToken && authorizationInfo.Token?.Length > 8
? authorizationInfo.Token.Substring(0, 8) + "..."
: authorizationInfo.Token ?? "null";
_logger.LogDebug(
"WebSocket authentication failed from {IP}. HasToken: {HasToken}, Token: {Token}",
context.Connection.RemoteIpAddress,
authorizationInfo.HasToken,
tokenPreview);
throw new SecurityException("Token is required");
}
@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Jellyfin.Data;
using Jellyfin.Data.Enums;
@@ -18,6 +19,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using Series = MediaBrowser.Controller.Entities.TV.Series;