mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Handling overall permissions
This commit is contained in:
parent
71c18092e5
commit
21e354bf00
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Authentication.Models;
|
using Kyoo.Authentication.Models;
|
||||||
@ -35,7 +36,7 @@ namespace Kyoo.Authentication
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IFilterMetadata Create(PermissionAttribute attribute)
|
public IFilterMetadata Create(PermissionAttribute attribute)
|
||||||
{
|
{
|
||||||
return new PermissionValidator(attribute.AsPermissionString(), _options);
|
return new PermissionValidator(attribute.Type, attribute.Kind, _options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -54,9 +55,9 @@ namespace Kyoo.Authentication
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly string _permission;
|
private readonly string _permission;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Information about partial items.
|
/// The kind of permission needed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly object _partialInfo;
|
private readonly Kind? _kind;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The permissions options to retrieve default permissions.
|
/// The permissions options to retrieve default permissions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -66,10 +67,12 @@ namespace Kyoo.Authentication
|
|||||||
/// Create a new permission validator with the given options
|
/// Create a new permission validator with the given options
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="permission">The permission to validate</param>
|
/// <param name="permission">The permission to validate</param>
|
||||||
|
/// <param name="kind">The kind of permission needed</param>
|
||||||
/// <param name="options">The option containing default values.</param>
|
/// <param name="options">The option containing default values.</param>
|
||||||
public PermissionValidator(string permission, IOptionsMonitor<PermissionOption> options)
|
public PermissionValidator(string permission, Kind kind, IOptionsMonitor<PermissionOption> options)
|
||||||
{
|
{
|
||||||
_permission = permission;
|
_permission = permission;
|
||||||
|
_kind = kind;
|
||||||
_options = options;
|
_options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +83,12 @@ namespace Kyoo.Authentication
|
|||||||
/// <param name="options">The option containing default values.</param>
|
/// <param name="options">The option containing default values.</param>
|
||||||
public PermissionValidator(object partialInfo, IOptionsMonitor<PermissionOption> options)
|
public PermissionValidator(object partialInfo, IOptionsMonitor<PermissionOption> options)
|
||||||
{
|
{
|
||||||
_partialInfo = partialInfo;
|
if (partialInfo is Kind kind)
|
||||||
|
_kind = kind;
|
||||||
|
else if (partialInfo is string perm)
|
||||||
|
_permission = perm;
|
||||||
|
else
|
||||||
|
throw new ArgumentException($"{nameof(partialInfo)} can only be a permission string or a kind.");
|
||||||
_options = options;
|
_options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,35 +97,46 @@ namespace Kyoo.Authentication
|
|||||||
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||||
{
|
{
|
||||||
string permission = _permission;
|
string permission = _permission;
|
||||||
|
Kind? kind = _kind;
|
||||||
|
|
||||||
if (_partialInfo != null)
|
if (permission == null || kind == null)
|
||||||
{
|
{
|
||||||
switch (context.HttpContext.Items["PermissionType"])
|
switch (context.HttpContext.Items["PermissionType"])
|
||||||
{
|
{
|
||||||
case string perm when _partialInfo is Kind kind:
|
case string perm:
|
||||||
permission = $"{perm}.{kind.ToString().ToLower()}";
|
permission = perm;
|
||||||
break;
|
break;
|
||||||
case Kind kind when _partialInfo is string partial:
|
case Kind kin:
|
||||||
permission = $"{partial}.{kind.ToString().ToLower()}";
|
kind = kin;
|
||||||
break;
|
break;
|
||||||
case null:
|
case null when kind != null:
|
||||||
context.HttpContext.Items["PermissionType"] = _partialInfo;
|
context.HttpContext.Items["PermissionType"] = kind;
|
||||||
|
return;
|
||||||
|
case null when permission != null:
|
||||||
|
context.HttpContext.Items["PermissionType"] = permission;
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException("Multiple non-matching partial permission attribute " +
|
throw new ArgumentException("Multiple non-matching partial permission attribute " +
|
||||||
"are not supported.");
|
"are not supported.");
|
||||||
}
|
}
|
||||||
|
if (permission == null || kind == null)
|
||||||
|
throw new ArgumentException("The permission type or kind is still missing after two partial " +
|
||||||
|
"permission attributes, this is unsupported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string permStr = $"{permission.ToLower()}.{kind.ToString()!.ToLower()}";
|
||||||
|
string overallStr = $"overall.{kind.ToString()!.ToLower()}";
|
||||||
AuthenticateResult res = await context.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
AuthenticateResult res = await context.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
|
||||||
if (res.Succeeded)
|
if (res.Succeeded)
|
||||||
{
|
{
|
||||||
if (res.Principal.GetPermissions().All(x => x != permission))
|
ICollection<string> permissions = res.Principal.GetPermissions();
|
||||||
|
if (permissions.All(x => x != permStr && x != overallStr))
|
||||||
context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
|
context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (res.Failure != null || _options.CurrentValue.Default.All(x => x != permission))
|
ICollection<string> permissions = _options.CurrentValue.Default ?? Array.Empty<string>();
|
||||||
|
if (res.Failure != null || permissions.All(x => x != permStr && x != overallStr))
|
||||||
context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized);
|
context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,11 @@ namespace Kyoo.Models.Permissions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The needed permission as string.
|
/// The needed permission as string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly string _permission;
|
public string Type { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// The needed permission kind.
|
||||||
|
/// </summary>
|
||||||
|
public Kind Kind { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ask a permission to run an action.
|
/// Ask a permission to run an action.
|
||||||
@ -38,7 +42,8 @@ namespace Kyoo.Models.Permissions
|
|||||||
{
|
{
|
||||||
if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
|
if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
|
||||||
type = type[..^3];
|
type = type[..^3];
|
||||||
_permission = $"{type.ToLower()}.{permission.ToString().ToLower()}";
|
Type = type.ToLower();
|
||||||
|
Kind = permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -56,7 +61,7 @@ namespace Kyoo.Models.Permissions
|
|||||||
/// <returns>The string representation.</returns>
|
/// <returns>The string representation.</returns>
|
||||||
public string AsPermissionString()
|
public string AsPermissionString()
|
||||||
{
|
{
|
||||||
return _permission;
|
return Type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
Kyoo/Controllers/PassthroughPermissionValidator.cs
Normal file
35
Kyoo/Controllers/PassthroughPermissionValidator.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using Kyoo.Models.Permissions;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Kyoo.Controllers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A permission validator that always validate permissions. This effectively disable the permission system.
|
||||||
|
/// </summary>
|
||||||
|
public class PassthroughPermissionValidator : IPermissionValidator
|
||||||
|
{
|
||||||
|
// ReSharper disable once SuggestBaseTypeForParameter
|
||||||
|
public PassthroughPermissionValidator(ILogger<PassthroughPermissionValidator> logger)
|
||||||
|
{
|
||||||
|
logger.LogWarning("No permission validator has been enabled, all users will have all permissions");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IFilterMetadata Create(PermissionAttribute attribute)
|
||||||
|
{
|
||||||
|
return new PassthroughValidator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IFilterMetadata Create(PartialPermissionAttribute attribute)
|
||||||
|
{
|
||||||
|
return new PassthroughValidator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An useless filter that does nothing.
|
||||||
|
/// </summary>
|
||||||
|
private class PassthroughValidator : IFilterMetadata { }
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models.Permissions;
|
||||||
using Kyoo.Tasks;
|
using Kyoo.Tasks;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
@ -93,6 +95,9 @@ namespace Kyoo
|
|||||||
}
|
}
|
||||||
|
|
||||||
services.AddTask<Crawler>();
|
services.AddTask<Crawler>();
|
||||||
|
|
||||||
|
if (services.All(x => x.ServiceType != typeof(IPermissionValidator)))
|
||||||
|
services.AddSingleton<IPermissionValidator, PassthroughPermissionValidator>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../Kyoo.Authentication/Kyoo.Authentication.csproj">
|
<ProjectReference Include="../Kyoo.Authentication/Kyoo.Authentication.csproj">
|
||||||
<!-- <ExcludeAssets>all</ExcludeAssets>-->
|
<ExcludeAssets>all</ExcludeAssets>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Kyoo.Authentication;
|
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Postgresql;
|
using Kyoo.Postgresql;
|
||||||
using Kyoo.Tasks;
|
using Kyoo.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.SpaServices.AngularCli;
|
using Microsoft.AspNetCore.SpaServices.AngularCli;
|
||||||
using Microsoft.AspNetCore.StaticFiles;
|
using Microsoft.AspNetCore.StaticFiles;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@ -48,8 +46,7 @@ namespace Kyoo
|
|||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_plugins = new PluginManager(hostProvider, _configuration, loggerFactory.CreateLogger<PluginManager>());
|
_plugins = new PluginManager(hostProvider, _configuration, loggerFactory.CreateLogger<PluginManager>());
|
||||||
|
|
||||||
_plugins.LoadPlugins(new IPlugin[] {new CoreModule(), new PostgresModule(configuration, host),
|
_plugins.LoadPlugins(new IPlugin[] {new CoreModule(), new PostgresModule(configuration, host)});
|
||||||
new AuthenticationModule(configuration, loggerFactory, host)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -32,8 +32,8 @@
|
|||||||
"password": "passphrase"
|
"password": "passphrase"
|
||||||
},
|
},
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"default": ["read", "play", "write", "admin"],
|
"default": ["overall.read", "overall.write", "overall.create", "overall.delete"],
|
||||||
"newUser": ["read", "play", "write", "admin", "task.read"]
|
"newUser": ["overall.read", "overall.write", "overall.create", "overall.delete"]
|
||||||
},
|
},
|
||||||
"profilePicturePath": "users/",
|
"profilePicturePath": "users/",
|
||||||
"clients": []
|
"clients": []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user