diff options
5 files changed, 82 insertions, 1 deletions
diff --git a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs index 392498c53..62d590b18 100644 --- a/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs +++ b/Jellyfin.Api/Auth/BaseAuthorizationHandler.cs @@ -1,4 +1,4 @@ -using System.Security.Claims; +using System.Security.Claims; using Jellyfin.Api.Helpers; using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; @@ -37,6 +37,16 @@ namespace Jellyfin.Api.Auth } /// <summary> + /// Gets a value indicating <see cref="INetworkManager"/> being used. + /// </summary> + protected INetworkManager NetworkManager => _networkManager; + + /// <summary> + /// Gets a value indicating the <see cref="HttpContextAccessor"/> being used. + /// </summary> + protected IHttpContextAccessor HttpContextAccessor => _httpContextAccessor; + + /// <summary> /// Validate authenticated claims. /// </summary> /// <param name="claimsPrincipal">Request claims.</param> diff --git a/Jellyfin.Api/Auth/LocalNetworkAccessPolicy/LocalNetworkAccessHandler.cs b/Jellyfin.Api/Auth/LocalNetworkAccessPolicy/LocalNetworkAccessHandler.cs new file mode 100644 index 000000000..d691c5594 --- /dev/null +++ b/Jellyfin.Api/Auth/LocalNetworkAccessPolicy/LocalNetworkAccessHandler.cs @@ -0,0 +1,46 @@ +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Library; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; + +namespace Jellyfin.Api.Auth.LocalNetworkAccessPolicy +{ + /// <summary> + /// Local access handler. + /// </summary> + public class LocalNetworkAccessHandler : BaseAuthorizationHandler<LocalNetworkAccessRequirement> + { + /// <summary> + /// Initializes a new instance of the <see cref="LocalNetworkAccessHandler"/> class. + /// </summary> + /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> + /// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param> + /// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param> + public LocalNetworkAccessHandler( + IUserManager userManager, + INetworkManager networkManager, + IHttpContextAccessor httpContextAccessor) + : base(userManager, networkManager, httpContextAccessor) + { + } + + /// <inheritdoc /> + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, LocalNetworkAccessRequirement requirement) + { + var ip = HttpContextAccessor.HttpContext?.Connection.RemoteIpAddress; + + // Loopback will be on LAN, so we can accept null. + if (ip == null || NetworkManager.IsInLocalNetwork(ip)) + { + context.Succeed(requirement); + } + else + { + context.Fail(); + } + + return Task.CompletedTask; + } + } +} diff --git a/Jellyfin.Api/Auth/LocalNetworkAccessPolicy/LocalNetworkAccessRequirement.cs b/Jellyfin.Api/Auth/LocalNetworkAccessPolicy/LocalNetworkAccessRequirement.cs new file mode 100644 index 000000000..29ca9c355 --- /dev/null +++ b/Jellyfin.Api/Auth/LocalNetworkAccessPolicy/LocalNetworkAccessRequirement.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Authorization; + +namespace Jellyfin.Api.Auth.LocalNetworkAccessPolicy +{ + /// <summary> + /// The local network authorization requirement. + /// </summary> + public class LocalNetworkAccessRequirement : IAuthorizationRequirement + { + } +} diff --git a/Jellyfin.Api/Constants/Policies.cs b/Jellyfin.Api/Constants/Policies.cs index 632dedb3c..b176bfa32 100644 --- a/Jellyfin.Api/Constants/Policies.cs +++ b/Jellyfin.Api/Constants/Policies.cs @@ -46,6 +46,11 @@ namespace Jellyfin.Api.Constants public const string LocalAccessOrRequiresElevation = "LocalAccessOrRequiresElevation"; /// <summary> + /// Policy name for requiring local LAN access. + /// </summary> + public const string LocalNetworkAccessPolicy = "LocalNetworkAccessPolicy"; + + /// <summary> /// Policy name for escaping schedule controls or requiring first time setup. /// </summary> public const string FirstTimeSetupOrIgnoreParentalControl = "FirstTimeSetupOrIgnoreParentalControl"; diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index f19e87aba..909f6b248 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -15,6 +15,7 @@ using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy; using Jellyfin.Api.Auth.IgnoreParentalControlPolicy; using Jellyfin.Api.Auth.LocalAccessOrRequiresElevationPolicy; using Jellyfin.Api.Auth.LocalAccessPolicy; +using Jellyfin.Api.Auth.LocalNetworkAccessPolicy; using Jellyfin.Api.Auth.RequiresElevationPolicy; using Jellyfin.Api.Auth.SyncPlayAccessPolicy; using Jellyfin.Api.Constants; @@ -61,6 +62,7 @@ namespace Jellyfin.Server.Extensions serviceCollection.AddSingleton<IAuthorizationHandler, IgnoreParentalControlHandler>(); serviceCollection.AddSingleton<IAuthorizationHandler, FirstTimeOrIgnoreParentalControlSetupHandler>(); serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessHandler>(); + serviceCollection.AddSingleton<IAuthorizationHandler, LocalNetworkAccessHandler>(); serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessOrRequiresElevationHandler>(); serviceCollection.AddSingleton<IAuthorizationHandler, RequiresElevationHandler>(); serviceCollection.AddSingleton<IAuthorizationHandler, SyncPlayAccessHandler>(); @@ -157,6 +159,13 @@ namespace Jellyfin.Server.Extensions policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.IsInGroup)); }); + options.AddPolicy( + Policies.LocalNetworkAccessPolicy, + policy => + { + policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); + policy.AddRequirements(new LocalNetworkAccessRequirement()); + }); }); } |
