aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Server
diff options
context:
space:
mode:
Diffstat (limited to 'Jellyfin.Server')
-rw-r--r--Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs143
-rw-r--r--Jellyfin.Server/Filters/SecurityRequirementsOperationFilter.cs67
2 files changed, 72 insertions, 138 deletions
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index e9af1cf83..968a8e58c 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -5,19 +5,15 @@ 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.LocalAccessOrRequiresElevationPolicy;
-using Jellyfin.Api.Auth.LocalAccessPolicy;
-using Jellyfin.Api.Auth.RequiresElevationPolicy;
+using Jellyfin.Api.Auth.FirstTimeSetupPolicy;
using Jellyfin.Api.Auth.SyncPlayAccessPolicy;
+using Jellyfin.Api.Auth.UserPermissionPolicy;
using Jellyfin.Api.Constants;
using Jellyfin.Api.Controllers;
using Jellyfin.Api.Formatters;
@@ -56,117 +52,34 @@ 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.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.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.AnonymousLanAccessPolicy, new AnonymousLanAccessRequirement());
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 +247,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/Filters/SecurityRequirementsOperationFilter.cs b/Jellyfin.Server/Filters/SecurityRequirementsOperationFilter.cs
index 4af670e9a..fb9f6d0a6 100644
--- a/Jellyfin.Server/Filters/SecurityRequirementsOperationFilter.cs
+++ b/Jellyfin.Server/Filters/SecurityRequirementsOperationFilter.cs
@@ -18,11 +18,17 @@ namespace Jellyfin.Server.Filters
{
var requiredScopes = new List<string>();
+ var requiresAuth = false;
// Add all method scopes.
foreach (var attribute in context.MethodInfo.GetCustomAttributes(true))
{
- if (attribute is AuthorizeAttribute authorizeAttribute
- && authorizeAttribute.Policy is not null
+ if (attribute is not AuthorizeAttribute authorizeAttribute)
+ {
+ continue;
+ }
+
+ requiresAuth = true;
+ if (authorizeAttribute.Policy is not null
&& !requiredScopes.Contains(authorizeAttribute.Policy, StringComparer.Ordinal))
{
requiredScopes.Add(authorizeAttribute.Policy);
@@ -35,8 +41,13 @@ namespace Jellyfin.Server.Filters
{
foreach (var attribute in controllerAttributes)
{
- if (attribute is AuthorizeAttribute authorizeAttribute
- && authorizeAttribute.Policy is not null
+ if (attribute is not AuthorizeAttribute authorizeAttribute)
+ {
+ continue;
+ }
+
+ requiresAuth = true;
+ if (authorizeAttribute.Policy is not null
&& !requiredScopes.Contains(authorizeAttribute.Policy, StringComparer.Ordinal))
{
requiredScopes.Add(authorizeAttribute.Policy);
@@ -44,35 +55,37 @@ namespace Jellyfin.Server.Filters
}
}
- if (requiredScopes.Count != 0)
+ if (!requiresAuth)
{
- if (!operation.Responses.ContainsKey("401"))
- {
- operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
- }
+ return;
+ }
- if (!operation.Responses.ContainsKey("403"))
- {
- operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" });
- }
+ if (!operation.Responses.ContainsKey("401"))
+ {
+ operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
+ }
- var scheme = new OpenApiSecurityScheme
+ if (!operation.Responses.ContainsKey("403"))
+ {
+ operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" });
+ }
+
+ var scheme = new OpenApiSecurityScheme
+ {
+ Reference = new OpenApiReference
{
- Reference = new OpenApiReference
- {
- Type = ReferenceType.SecurityScheme,
- Id = AuthenticationSchemes.CustomAuthentication
- }
- };
+ Type = ReferenceType.SecurityScheme,
+ Id = AuthenticationSchemes.CustomAuthentication
+ }
+ };
- operation.Security = new List<OpenApiSecurityRequirement>
+ operation.Security = new List<OpenApiSecurityRequirement>
+ {
+ new OpenApiSecurityRequirement
{
- new OpenApiSecurityRequirement
- {
- [scheme] = requiredScopes
- }
- };
- }
+ [scheme] = requiredScopes
+ }
+ };
}
}
}