mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Move request validation to auth policies
This commit is contained in:
parent
b57ace7888
commit
7e0ea296c3
@ -102,11 +102,6 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void NewGroup(SessionInfo session, NewGroupRequest request, CancellationToken cancellationToken)
|
public void NewGroup(SessionInfo session, NewGroupRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (!IsRequestValid(session, request))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Locking required to access list of groups.
|
// Locking required to access list of groups.
|
||||||
lock (_groupsLock)
|
lock (_groupsLock)
|
||||||
{
|
{
|
||||||
@ -132,11 +127,6 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void JoinGroup(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken)
|
public void JoinGroup(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (!IsRequestValid(session, request))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = _userManager.GetUserById(session.UserId);
|
var user = _userManager.GetUserById(session.UserId);
|
||||||
|
|
||||||
// Locking required to access list of groups.
|
// Locking required to access list of groups.
|
||||||
@ -190,11 +180,6 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void LeaveGroup(SessionInfo session, LeaveGroupRequest request, CancellationToken cancellationToken)
|
public void LeaveGroup(SessionInfo session, LeaveGroupRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (!IsRequestValid(session, request))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Locking required to access list of groups.
|
// Locking required to access list of groups.
|
||||||
lock (_groupsLock)
|
lock (_groupsLock)
|
||||||
{
|
{
|
||||||
@ -230,11 +215,6 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public List<GroupInfoDto> ListGroups(SessionInfo session, ListGroupsRequest request)
|
public List<GroupInfoDto> ListGroups(SessionInfo session, ListGroupsRequest request)
|
||||||
{
|
{
|
||||||
if (!IsRequestValid(session, request))
|
|
||||||
{
|
|
||||||
return new List<GroupInfoDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = _userManager.GetUserById(session.UserId);
|
var user = _userManager.GetUserById(session.UserId);
|
||||||
List<GroupInfoDto> list = new List<GroupInfoDto>();
|
List<GroupInfoDto> list = new List<GroupInfoDto>();
|
||||||
|
|
||||||
@ -260,11 +240,6 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void HandleRequest(SessionInfo session, IGroupPlaybackRequest request, CancellationToken cancellationToken)
|
public void HandleRequest(SessionInfo session, IGroupPlaybackRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (!IsRequestValid(session, request))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IGroupController group;
|
IGroupController group;
|
||||||
lock (_mapsLock)
|
lock (_mapsLock)
|
||||||
{
|
{
|
||||||
@ -417,42 +392,5 @@ namespace Emby.Server.Implementations.SyncPlay
|
|||||||
throw new InvalidOperationException("Session was in wrong group!");
|
throw new InvalidOperationException("Session was in wrong group!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if a given session is allowed to make a given request.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="session">The session.</param>
|
|
||||||
/// <param name="request">The request.</param>
|
|
||||||
/// <returns><c>true</c> if the request is valid, <c>false</c> otherwise. Will return <c>false</c> also when session or request is null.</returns>
|
|
||||||
private bool IsRequestValid(SessionInfo session, ISyncPlayRequest request)
|
|
||||||
{
|
|
||||||
if (session == null || (request == null))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = _userManager.GetUserById(session.UserId);
|
|
||||||
|
|
||||||
if (user.SyncPlayAccess == SyncPlayAccess.None)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Session {SessionId} requested {RequestType} but does not have access to SyncPlay.", session.Id, request.Type);
|
|
||||||
|
|
||||||
// TODO: rename to a more generic error. Next PR will fix this.
|
|
||||||
var error = new GroupUpdate<string>(Guid.Empty, GroupUpdateType.JoinGroupDenied, string.Empty);
|
|
||||||
_sessionManager.SendSyncPlayGroupUpdate(session, error, CancellationToken.None);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.Type.Equals(RequestType.NewGroup) && user.SyncPlayAccess != SyncPlayAccess.CreateAndJoinGroups)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Session {SessionId} does not have permission to create groups.", session.Id);
|
|
||||||
|
|
||||||
var error = new GroupUpdate<string>(Guid.Empty, GroupUpdateType.CreateGroupDenied, string.Empty);
|
|
||||||
_sessionManager.SendSyncPlayGroupUpdate(session, error, CancellationToken.None);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Jellyfin.Api.Helpers;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
|
namespace Jellyfin.Api.Auth.SyncPlayAccessPolicy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default authorization handler.
|
||||||
|
/// </summary>
|
||||||
|
public class SyncPlayAccessHandler : BaseAuthorizationHandler<SyncPlayAccessRequirement>
|
||||||
|
{
|
||||||
|
private readonly IUserManager _userManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SyncPlayAccessHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
||||||
|
/// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param>
|
||||||
|
/// <param name="httpContextAccessor">Instance of the <see cref="IHttpContextAccessor"/> interface.</param>
|
||||||
|
public SyncPlayAccessHandler(
|
||||||
|
IUserManager userManager,
|
||||||
|
INetworkManager networkManager,
|
||||||
|
IHttpContextAccessor httpContextAccessor)
|
||||||
|
: base(userManager, networkManager, httpContextAccessor)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SyncPlayAccessRequirement requirement)
|
||||||
|
{
|
||||||
|
if (!ValidateClaims(context.User))
|
||||||
|
{
|
||||||
|
context.Fail();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = ClaimHelpers.GetUserId(context.User);
|
||||||
|
var user = _userManager.GetUserById(userId!.Value);
|
||||||
|
|
||||||
|
if ((requirement.RequiredAccess.HasValue && user.SyncPlayAccess == requirement.RequiredAccess)
|
||||||
|
|| (user.SyncPlayAccess == SyncPlayAccess.JoinGroups || user.SyncPlayAccess == SyncPlayAccess.CreateAndJoinGroups))
|
||||||
|
{
|
||||||
|
context.Succeed(requirement);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
using Jellyfin.Data.Enums;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace Jellyfin.Api.Auth.SyncPlayAccessPolicy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The default authorization requirement.
|
||||||
|
/// </summary>
|
||||||
|
public class SyncPlayAccessRequirement : IAuthorizationRequirement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SyncPlayAccessRequirement"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requiredAccess">A value of <see cref="SyncPlayAccess"/>.</param>
|
||||||
|
public SyncPlayAccessRequirement(SyncPlayAccess requiredAccess)
|
||||||
|
{
|
||||||
|
RequiredAccess = requiredAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SyncPlayAccessRequirement"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public SyncPlayAccessRequirement()
|
||||||
|
{
|
||||||
|
RequiredAccess = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the required SyncPlay access.
|
||||||
|
/// </summary>
|
||||||
|
public SyncPlayAccess? RequiredAccess { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -49,5 +49,15 @@ namespace Jellyfin.Api.Constants
|
|||||||
/// Policy name for escaping schedule controls or requiring first time setup.
|
/// Policy name for escaping schedule controls or requiring first time setup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string FirstTimeSetupOrIgnoreParentalControl = "FirstTimeSetupOrIgnoreParentalControl";
|
public const string FirstTimeSetupOrIgnoreParentalControl = "FirstTimeSetupOrIgnoreParentalControl";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Policy name for requiring access to SyncPlay.
|
||||||
|
/// </summary>
|
||||||
|
public const string SyncPlayAccess = "SyncPlayAccess";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Policy name for requiring group creation access to SyncPlay.
|
||||||
|
/// </summary>
|
||||||
|
public const string SyncPlayCreateGroupAccess = "SyncPlayCreateGroupAccess";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sync play controller.
|
/// The sync play controller.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Authorize(Policy = Policies.DefaultAuthorization)]
|
[Authorize(Policy = Policies.SyncPlayAccess)]
|
||||||
public class SyncPlayController : BaseJellyfinApiController
|
public class SyncPlayController : BaseJellyfinApiController
|
||||||
{
|
{
|
||||||
private readonly ISessionManager _sessionManager;
|
private readonly ISessionManager _sessionManager;
|
||||||
@ -51,6 +51,7 @@ namespace Jellyfin.Api.Controllers
|
|||||||
/// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
|
/// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
|
||||||
[HttpPost("New")]
|
[HttpPost("New")]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
[Authorize(Policy = Policies.SyncPlayCreateGroupAccess)]
|
||||||
public ActionResult SyncPlayCreateGroup(
|
public ActionResult SyncPlayCreateGroup(
|
||||||
[FromBody, Required] NewGroupRequestBody requestData)
|
[FromBody, Required] NewGroupRequestBody requestData)
|
||||||
{
|
{
|
||||||
|
@ -15,9 +15,11 @@ using Jellyfin.Api.Auth.IgnoreParentalControlPolicy;
|
|||||||
using Jellyfin.Api.Auth.LocalAccessOrRequiresElevationPolicy;
|
using Jellyfin.Api.Auth.LocalAccessOrRequiresElevationPolicy;
|
||||||
using Jellyfin.Api.Auth.LocalAccessPolicy;
|
using Jellyfin.Api.Auth.LocalAccessPolicy;
|
||||||
using Jellyfin.Api.Auth.RequiresElevationPolicy;
|
using Jellyfin.Api.Auth.RequiresElevationPolicy;
|
||||||
|
using Jellyfin.Api.Auth.SyncPlayAccessPolicy;
|
||||||
using Jellyfin.Api.Constants;
|
using Jellyfin.Api.Constants;
|
||||||
using Jellyfin.Api.Controllers;
|
using Jellyfin.Api.Controllers;
|
||||||
using Jellyfin.Api.ModelBinders;
|
using Jellyfin.Api.ModelBinders;
|
||||||
|
using Jellyfin.Data.Enums;
|
||||||
using Jellyfin.Server.Configuration;
|
using Jellyfin.Server.Configuration;
|
||||||
using Jellyfin.Server.Filters;
|
using Jellyfin.Server.Filters;
|
||||||
using Jellyfin.Server.Formatters;
|
using Jellyfin.Server.Formatters;
|
||||||
@ -58,6 +60,7 @@ namespace Jellyfin.Server.Extensions
|
|||||||
serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessHandler>();
|
serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessHandler>();
|
||||||
serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessOrRequiresElevationHandler>();
|
serviceCollection.AddSingleton<IAuthorizationHandler, LocalAccessOrRequiresElevationHandler>();
|
||||||
serviceCollection.AddSingleton<IAuthorizationHandler, RequiresElevationHandler>();
|
serviceCollection.AddSingleton<IAuthorizationHandler, RequiresElevationHandler>();
|
||||||
|
serviceCollection.AddSingleton<IAuthorizationHandler, SyncPlayAccessHandler>();
|
||||||
return serviceCollection.AddAuthorizationCore(options =>
|
return serviceCollection.AddAuthorizationCore(options =>
|
||||||
{
|
{
|
||||||
options.AddPolicy(
|
options.AddPolicy(
|
||||||
@ -123,6 +126,20 @@ namespace Jellyfin.Server.Extensions
|
|||||||
policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
|
policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
|
||||||
policy.AddRequirements(new RequiresElevationRequirement());
|
policy.AddRequirements(new RequiresElevationRequirement());
|
||||||
});
|
});
|
||||||
|
options.AddPolicy(
|
||||||
|
Policies.SyncPlayAccess,
|
||||||
|
policy =>
|
||||||
|
{
|
||||||
|
policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
|
||||||
|
policy.AddRequirements(new SyncPlayAccessRequirement());
|
||||||
|
});
|
||||||
|
options.AddPolicy(
|
||||||
|
Policies.SyncPlayCreateGroupAccess,
|
||||||
|
policy =>
|
||||||
|
{
|
||||||
|
policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
|
||||||
|
policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccess.CreateAndJoinGroups));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user