CustomAuthenticationHandler.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #nullable enable
  2. using System.Globalization;
  3. using System.Security.Authentication;
  4. using System.Security.Claims;
  5. using System.Text.Encodings.Web;
  6. using System.Threading.Tasks;
  7. using Jellyfin.Api.Constants;
  8. using Jellyfin.Data.Enums;
  9. using MediaBrowser.Controller.Net;
  10. using Microsoft.AspNetCore.Authentication;
  11. using Microsoft.Extensions.Logging;
  12. using Microsoft.Extensions.Options;
  13. namespace Jellyfin.Api.Auth
  14. {
  15. /// <summary>
  16. /// Custom authentication handler wrapping the legacy authentication.
  17. /// </summary>
  18. public class CustomAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
  19. {
  20. private readonly IAuthService _authService;
  21. /// <summary>
  22. /// Initializes a new instance of the <see cref="CustomAuthenticationHandler" /> class.
  23. /// </summary>
  24. /// <param name="authService">The jellyfin authentication service.</param>
  25. /// <param name="options">Options monitor.</param>
  26. /// <param name="logger">The logger.</param>
  27. /// <param name="encoder">The url encoder.</param>
  28. /// <param name="clock">The system clock.</param>
  29. public CustomAuthenticationHandler(
  30. IAuthService authService,
  31. IOptionsMonitor<AuthenticationSchemeOptions> options,
  32. ILoggerFactory logger,
  33. UrlEncoder encoder,
  34. ISystemClock clock) : base(options, logger, encoder, clock)
  35. {
  36. _authService = authService;
  37. }
  38. /// <inheritdoc />
  39. protected override Task<AuthenticateResult> HandleAuthenticateAsync()
  40. {
  41. try
  42. {
  43. var authorizationInfo = _authService.Authenticate(Request);
  44. if (authorizationInfo == null)
  45. {
  46. return Task.FromResult(AuthenticateResult.NoResult());
  47. // TODO return when legacy API is removed.
  48. // Don't spam the log with "Invalid User"
  49. // return Task.FromResult(AuthenticateResult.Fail("Invalid user"));
  50. }
  51. var claims = new[]
  52. {
  53. new Claim(ClaimTypes.Name, authorizationInfo.User.Username),
  54. new Claim(ClaimTypes.Role, value: authorizationInfo.User.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User),
  55. new Claim(InternalClaimTypes.UserId, authorizationInfo.UserId.ToString("N", CultureInfo.InvariantCulture)),
  56. new Claim(InternalClaimTypes.DeviceId, authorizationInfo.DeviceId),
  57. new Claim(InternalClaimTypes.Device, authorizationInfo.Device),
  58. new Claim(InternalClaimTypes.Client, authorizationInfo.Client),
  59. new Claim(InternalClaimTypes.Version, authorizationInfo.Version),
  60. new Claim(InternalClaimTypes.Token, authorizationInfo.Token),
  61. };
  62. var identity = new ClaimsIdentity(claims, Scheme.Name);
  63. var principal = new ClaimsPrincipal(identity);
  64. var ticket = new AuthenticationTicket(principal, Scheme.Name);
  65. return Task.FromResult(AuthenticateResult.Success(ticket));
  66. }
  67. catch (AuthenticationException ex)
  68. {
  69. return Task.FromResult(AuthenticateResult.Fail(ex));
  70. }
  71. catch (SecurityException ex)
  72. {
  73. return Task.FromResult(AuthenticateResult.Fail(ex));
  74. }
  75. }
  76. }
  77. }