< Summary - Jellyfin

Information
Class: Jellyfin.Server.Filters.SecurityRequirementsOperationFilter
Assembly: jellyfin
File(s): /srv/git/jellyfin/Jellyfin.Server/Filters/SecurityRequirementsOperationFilter.cs
Line coverage
100%
Covered lines: 38
Uncovered lines: 0
Coverable lines: 38
Total lines: 98
Line coverage: 100%
Branch coverage
96%
Covered branches: 25
Total branches: 26
Branch coverage: 96.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 10/25/2025 - 12:09:58 AM Line coverage: 100% (38/38) Branch coverage: 96.1% (25/26) Total lines: 98 10/25/2025 - 12:09:58 AM Line coverage: 100% (38/38) Branch coverage: 96.1% (25/26) Total lines: 98

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%11100%
Apply(...)96.15%2626100%

File(s)

/srv/git/jellyfin/Jellyfin.Server/Filters/SecurityRequirementsOperationFilter.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using Jellyfin.Api.Auth.DefaultAuthorizationPolicy;
 5using Jellyfin.Api.Constants;
 6using Jellyfin.Extensions;
 7using Microsoft.AspNetCore.Authorization;
 8using Microsoft.OpenApi.Models;
 9using Swashbuckle.AspNetCore.SwaggerGen;
 10
 11namespace Jellyfin.Server.Filters;
 12
 13/// <summary>
 14/// Security requirement operation filter.
 15/// </summary>
 16public class SecurityRequirementsOperationFilter : IOperationFilter
 17{
 18    private const string DefaultAuthPolicy = "DefaultAuthorization";
 119    private static readonly Type _attributeType = typeof(AuthorizeAttribute);
 20
 21    private readonly IAuthorizationPolicyProvider _authorizationPolicyProvider;
 22
 23    /// <summary>
 24    /// Initializes a new instance of the <see cref="SecurityRequirementsOperationFilter"/> class.
 25    /// </summary>
 26    /// <param name="authorizationPolicyProvider">The authorization policy provider.</param>
 27    public SecurityRequirementsOperationFilter(IAuthorizationPolicyProvider authorizationPolicyProvider)
 28    {
 2029        _authorizationPolicyProvider = authorizationPolicyProvider;
 2030    }
 31
 32    /// <inheritdoc />
 33    public void Apply(OpenApiOperation operation, OperationFilterContext context)
 34    {
 38735        var requiredScopes = new List<string>();
 36
 38737        var requiresAuth = false;
 38        // Add all method scopes.
 110039        foreach (var authorizeAttribute in context.MethodInfo.GetCustomAttributes(_attributeType, true).Cast<AuthorizeAt
 40        {
 16341            requiresAuth = true;
 16342            var policy = authorizeAttribute.Policy ?? DefaultAuthPolicy;
 16343            if (!requiredScopes.Contains(policy, StringComparer.Ordinal))
 44            {
 16345                requiredScopes.Add(policy);
 46            }
 47        }
 48
 49        // Add controller scopes if any.
 38750        var controllerAttributes = context.MethodInfo.DeclaringType?.GetCustomAttributes(_attributeType, true).Cast<Auth
 38751        if (controllerAttributes is not null)
 52        {
 116053            foreach (var authorizeAttribute in controllerAttributes)
 54            {
 19355                requiresAuth = true;
 19356                var policy = authorizeAttribute.Policy ?? DefaultAuthPolicy;
 19357                if (!requiredScopes.Contains(policy, StringComparer.Ordinal))
 58                {
 19359                    requiredScopes.Add(policy);
 60                }
 61            }
 62        }
 63
 38764        if (!requiresAuth)
 65        {
 5966            return;
 67        }
 68
 32869        operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
 32870        operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });
 71
 32872        var scheme = new OpenApiSecurityScheme
 32873        {
 32874            Reference = new OpenApiReference
 32875            {
 32876                Type = ReferenceType.SecurityScheme,
 32877                Id = AuthenticationSchemes.CustomAuthentication
 32878            },
 32879        };
 80
 81        // Add DefaultAuthorization scope to any endpoint that has a policy with a requirement that is a subset of Defau
 32882        if (!requiredScopes.Contains(DefaultAuthPolicy.AsSpan(), StringComparison.Ordinal))
 83        {
 55184            foreach (var scope in requiredScopes)
 85            {
 16386                var authorizationPolicy = _authorizationPolicyProvider.GetPolicyAsync(scope).GetAwaiter().GetResult();
 16387                if (authorizationPolicy is not null
 16388                    && authorizationPolicy.Requirements.Any(r => r is DefaultAuthorizationRequirement))
 89                {
 10190                    requiredScopes.Add(DefaultAuthPolicy);
 10191                    break;
 92                }
 93            }
 94        }
 95
 32896        operation.Security = [new OpenApiSecurityRequirement { [scheme] = requiredScopes }];
 32897    }
 98}