using System.Globalization; using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Net; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Jellyfin.Api.Auth { /// /// Custom authentication handler wrapping the legacy authentication. /// public class CustomAuthenticationHandler : AuthenticationHandler { private readonly IAuthService _authService; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// The jellyfin authentication service. /// Options monitor. /// The logger. /// The url encoder. /// The system clock. public CustomAuthenticationHandler( IAuthService authService, IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { _authService = authService; _logger = logger.CreateLogger(); } /// protected override Task HandleAuthenticateAsync() { try { var authorizationInfo = _authService.Authenticate(Request); var role = UserRoles.User; if (authorizationInfo.IsApiKey || authorizationInfo.User.HasPermission(PermissionKind.IsAdministrator)) { role = UserRoles.Administrator; } var claims = new[] { new Claim(ClaimTypes.Name, authorizationInfo.User?.Username ?? string.Empty), new Claim(ClaimTypes.Role, role), new Claim(InternalClaimTypes.UserId, authorizationInfo.UserId.ToString("N", CultureInfo.InvariantCulture)), new Claim(InternalClaimTypes.DeviceId, authorizationInfo.DeviceId), new Claim(InternalClaimTypes.Device, authorizationInfo.Device), new Claim(InternalClaimTypes.Client, authorizationInfo.Client), new Claim(InternalClaimTypes.Version, authorizationInfo.Version), new Claim(InternalClaimTypes.Token, authorizationInfo.Token), new Claim(InternalClaimTypes.IsApiKey, authorizationInfo.IsApiKey.ToString(CultureInfo.InvariantCulture)) }; var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return Task.FromResult(AuthenticateResult.Success(ticket)); } catch (AuthenticationException ex) { _logger.LogDebug(ex, "Error authenticating with {Handler}", nameof(CustomAuthenticationHandler)); return Task.FromResult(AuthenticateResult.NoResult()); } catch (SecurityException ex) { _logger.LogDebug(ex, "Error authenticating with {Handler}", nameof(CustomAuthenticationHandler)); return Task.FromResult(AuthenticateResult.NoResult()); } } } }