diff options
Diffstat (limited to 'Jellyfin.Server/Extensions')
3 files changed, 128 insertions, 113 deletions
diff --git a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs index e29167747..463ca7321 100644 --- a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; +using Jellyfin.Api.Middleware; using Jellyfin.Networking.Configuration; -using Jellyfin.Server.Middleware; using MediaBrowser.Controller.Configuration; using Microsoft.AspNetCore.Builder; using Microsoft.OpenApi.Models; diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index f74152405..9867c9e47 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -5,28 +5,24 @@ using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; +using System.Security.Claims; using Emby.Server.Implementations; using Jellyfin.Api.Auth; using Jellyfin.Api.Auth.AnonymousLanAccessPolicy; using Jellyfin.Api.Auth.DefaultAuthorizationPolicy; -using Jellyfin.Api.Auth.DownloadPolicy; -using Jellyfin.Api.Auth.FirstTimeOrIgnoreParentalControlSetupPolicy; -using Jellyfin.Api.Auth.FirstTimeSetupOrDefaultPolicy; -using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy; -using Jellyfin.Api.Auth.IgnoreParentalControlPolicy; +using Jellyfin.Api.Auth.FirstTimeSetupPolicy; using Jellyfin.Api.Auth.LocalAccessOrRequiresElevationPolicy; -using Jellyfin.Api.Auth.LocalAccessPolicy; -using Jellyfin.Api.Auth.RequiresElevationPolicy; using Jellyfin.Api.Auth.SyncPlayAccessPolicy; +using Jellyfin.Api.Auth.UserPermissionPolicy; using Jellyfin.Api.Constants; using Jellyfin.Api.Controllers; +using Jellyfin.Api.Formatters; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; using Jellyfin.Extensions.Json; using Jellyfin.Networking.Configuration; using Jellyfin.Server.Configuration; using Jellyfin.Server.Filters; -using Jellyfin.Server.Formatters; using MediaBrowser.Common.Net; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Session; @@ -56,117 +52,38 @@ namespace Jellyfin.Server.Extensions /// <returns>The updated service collection.</returns> public static IServiceCollection AddJellyfinApiAuthorization(this IServiceCollection serviceCollection) { + // The default handler must be first so that it is evaluated first serviceCollection.AddSingleton<IAuthorizationHandler, DefaultAuthorizationHandler>(); - serviceCollection.AddSingleton<IAuthorizationHandler, DownloadHandler>(); - serviceCollection.AddSingleton<IAuthorizationHandler, FirstTimeSetupOrDefaultHandler>(); - serviceCollection.AddSingleton<IAuthorizationHandler, FirstTimeSetupOrElevatedHandler>(); - serviceCollection.AddSingleton<IAuthorizationHandler, IgnoreParentalControlHandler>(); - serviceCollection.AddSingleton<IAuthorizationHandler, FirstTimeOrIgnoreParentalControlSetupHandler>(); - serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessHandler>(); + serviceCollection.AddSingleton<IAuthorizationHandler, UserPermissionHandler>(); + serviceCollection.AddSingleton<IAuthorizationHandler, FirstTimeSetupHandler>(); serviceCollection.AddSingleton<IAuthorizationHandler, AnonymousLanAccessHandler>(); - serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessOrRequiresElevationHandler>(); - serviceCollection.AddSingleton<IAuthorizationHandler, RequiresElevationHandler>(); serviceCollection.AddSingleton<IAuthorizationHandler, SyncPlayAccessHandler>(); + return serviceCollection.AddAuthorizationCore(options => { - options.AddPolicy( - Policies.DefaultAuthorization, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new DefaultAuthorizationRequirement()); - }); - options.AddPolicy( - Policies.Download, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new DownloadRequirement()); - }); - options.AddPolicy( - Policies.FirstTimeSetupOrDefault, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new FirstTimeSetupOrDefaultRequirement()); - }); - options.AddPolicy( - Policies.FirstTimeSetupOrElevated, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new FirstTimeSetupOrElevatedRequirement()); - }); - options.AddPolicy( - Policies.IgnoreParentalControl, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new IgnoreParentalControlRequirement()); - }); - options.AddPolicy( - Policies.FirstTimeSetupOrIgnoreParentalControl, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new FirstTimeOrIgnoreParentalControlSetupRequirement()); - }); - options.AddPolicy( - Policies.LocalAccessOnly, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new LocalAccessRequirement()); - }); - options.AddPolicy( - Policies.LocalAccessOrRequiresElevation, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new LocalAccessOrRequiresElevationRequirement()); - }); + options.DefaultPolicy = new AuthorizationPolicyBuilder() + .AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication) + .AddRequirements(new DefaultAuthorizationRequirement()) + .Build(); + + options.AddPolicy(Policies.AnonymousLanAccessPolicy, new AnonymousLanAccessRequirement()); + options.AddPolicy(Policies.CollectionManagement, new UserPermissionRequirement(PermissionKind.EnableCollectionManagement)); + options.AddPolicy(Policies.Download, new UserPermissionRequirement(PermissionKind.EnableContentDownloading)); + options.AddPolicy(Policies.FirstTimeSetupOrDefault, new FirstTimeSetupRequirement(requireAdmin: false)); + options.AddPolicy(Policies.FirstTimeSetupOrElevated, new FirstTimeSetupRequirement()); + options.AddPolicy(Policies.FirstTimeSetupOrIgnoreParentalControl, new FirstTimeSetupRequirement(false, false)); + options.AddPolicy(Policies.IgnoreParentalControl, new DefaultAuthorizationRequirement(validateParentalSchedule: false)); + options.AddPolicy(Policies.LiveTvAccess, new UserPermissionRequirement(PermissionKind.EnableLiveTvAccess)); + options.AddPolicy(Policies.LiveTvManagement, new UserPermissionRequirement(PermissionKind.EnableLiveTvManagement)); + options.AddPolicy(Policies.LocalAccessOrRequiresElevation, new LocalAccessOrRequiresElevationRequirement()); + options.AddPolicy(Policies.SyncPlayHasAccess, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.HasAccess)); + options.AddPolicy(Policies.SyncPlayCreateGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.CreateGroup)); + options.AddPolicy(Policies.SyncPlayJoinGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.JoinGroup)); + options.AddPolicy(Policies.SyncPlayIsInGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.IsInGroup)); options.AddPolicy( Policies.RequiresElevation, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new RequiresElevationRequirement()); - }); - options.AddPolicy( - Policies.SyncPlayHasAccess, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.HasAccess)); - }); - options.AddPolicy( - Policies.SyncPlayCreateGroup, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.CreateGroup)); - }); - options.AddPolicy( - Policies.SyncPlayJoinGroup, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.JoinGroup)); - }); - options.AddPolicy( - Policies.SyncPlayIsInGroup, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.IsInGroup)); - }); - options.AddPolicy( - Policies.AnonymousLanAccessPolicy, - policy => - { - policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication); - policy.AddRequirements(new AnonymousLanAccessRequirement()); - }); + policy => policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication) + .RequireClaim(ClaimTypes.Role, UserRoles.Administrator)); }); } @@ -334,6 +251,14 @@ namespace Jellyfin.Server.Extensions }); } + private static void AddPolicy(this AuthorizationOptions authorizationOptions, string policyName, IAuthorizationRequirement authorizationRequirement) + { + authorizationOptions.AddPolicy(policyName, policy => + { + policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication).AddRequirements(authorizationRequirement); + }); + } + /// <summary> /// Sets up the proxy configuration based on the addresses in <paramref name="allowedProxies"/>. /// </summary> diff --git a/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs b/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs new file mode 100644 index 000000000..58d3e1b2d --- /dev/null +++ b/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs @@ -0,0 +1,90 @@ +using System; +using System.IO; +using System.Net; +using Jellyfin.Server.Helpers; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Extensions; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Extensions; + +/// <summary> +/// Extensions for configuring the web host builder. +/// </summary> +public static class WebHostBuilderExtensions +{ + /// <summary> + /// Configure the web host builder. + /// </summary> + /// <param name="builder">The builder to configure.</param> + /// <param name="appHost">The application host.</param> + /// <param name="startupConfig">The application configuration.</param> + /// <param name="appPaths">The application paths.</param> + /// <param name="logger">The logger.</param> + /// <returns>The configured web host builder.</returns> + public static IWebHostBuilder ConfigureWebHostBuilder( + this IWebHostBuilder builder, + CoreAppHost appHost, + IConfiguration startupConfig, + IApplicationPaths appPaths, + ILogger logger) + { + return builder + .UseKestrel((builderContext, options) => + { + var addresses = appHost.NetManager.GetAllBindInterfaces(); + + bool flagged = false; + foreach (IPObject netAdd in addresses) + { + logger.LogInformation("Kestrel listening on {Address}", IPAddress.IPv6Any.Equals(netAdd.Address) ? "All Addresses" : netAdd); + options.Listen(netAdd.Address, appHost.HttpPort); + if (appHost.ListenWithHttps) + { + options.Listen( + netAdd.Address, + appHost.HttpsPort, + listenOptions => listenOptions.UseHttps(appHost.Certificate)); + } + else if (builderContext.HostingEnvironment.IsDevelopment()) + { + try + { + options.Listen( + netAdd.Address, + appHost.HttpsPort, + listenOptions => listenOptions.UseHttps()); + } + catch (InvalidOperationException) + { + if (!flagged) + { + logger.LogWarning("Failed to listen to HTTPS using the ASP.NET Core HTTPS development certificate. Please ensure it has been installed and set as trusted"); + flagged = true; + } + } + } + } + + // Bind to unix socket (only on unix systems) + if (startupConfig.UseUnixSocket() && Environment.OSVersion.Platform == PlatformID.Unix) + { + var socketPath = StartupHelpers.GetUnixSocketPath(startupConfig, appPaths); + + // Workaround for https://github.com/aspnet/AspNetCore/issues/14134 + if (File.Exists(socketPath)) + { + File.Delete(socketPath); + } + + options.ListenUnixSocket(socketPath); + logger.LogInformation("Kestrel listening to unix socket {SocketPath}", socketPath); + } + }) + .UseStartup(_ => new Startup(appHost)); + } +} |
