aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server/Extensions
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Server/Extensions')
-rw-r--r--Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs2
-rw-r--r--Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs149
-rw-r--r--Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs90
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));
+ }
+}