2
0
Эх сурвалжийг харах

Update authorization policies for SyncPlay

Ionut Andrei Oanca 4 жил өмнө
parent
commit
499f3ee950

+ 44 - 0
Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs

@@ -41,6 +41,12 @@ namespace Emby.Server.Implementations.SyncPlay
         /// </summary>
         private readonly ILibraryManager _libraryManager;
 
+        /// <summary>
+        /// The map between users and counter of active sessions.
+        /// </summary>
+        private readonly ConcurrentDictionary<Guid, int> _activeUsers =
+            new ConcurrentDictionary<Guid, int>();
+
         /// <summary>
         /// The map between sessions and groups.
         /// </summary>
@@ -122,6 +128,7 @@ namespace Emby.Server.Implementations.SyncPlay
                     throw new InvalidOperationException("Could not add session to group!");
                 }
 
+                UpdateSessionsCounter(session.UserId, 1);
                 group.CreateGroup(session, request, cancellationToken);
             }
         }
@@ -172,6 +179,7 @@ namespace Emby.Server.Implementations.SyncPlay
                         if (existingGroup.GroupId.Equals(request.GroupId))
                         {
                             // Restore session.
+                            UpdateSessionsCounter(session.UserId, 1);
                             group.SessionJoin(session, request, cancellationToken);
                             return;
                         }
@@ -185,6 +193,7 @@ namespace Emby.Server.Implementations.SyncPlay
                         throw new InvalidOperationException("Could not add session to group!");
                     }
 
+                    UpdateSessionsCounter(session.UserId, 1);
                     group.SessionJoin(session, request, cancellationToken);
                 }
             }
@@ -223,6 +232,7 @@ namespace Emby.Server.Implementations.SyncPlay
                             throw new InvalidOperationException("Could not remove session from group!");
                         }
 
+                        UpdateSessionsCounter(session.UserId, -1);
                         group.SessionLeave(session, request, cancellationToken);
 
                         if (group.IsGroupEmpty())
@@ -318,6 +328,19 @@ namespace Emby.Server.Implementations.SyncPlay
             }
         }
 
+        /// <inheritdoc />
+        public bool IsUserActive(Guid userId)
+        {
+            if (_activeUsers.TryGetValue(userId, out var sessionsCounter))
+            {
+                return sessionsCounter > 0;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
         /// <summary>
         /// Releases unmanaged and optionally managed resources.
         /// </summary>
@@ -343,5 +366,26 @@ namespace Emby.Server.Implementations.SyncPlay
                 JoinGroup(session, request, CancellationToken.None);
             }
         }
+
+        private void UpdateSessionsCounter(Guid userId, int toAdd)
+        {
+            // Update sessions counter.
+            var newSessionsCounter = _activeUsers.AddOrUpdate(
+                userId,
+                1,
+                (key, sessionsCounter) => sessionsCounter + toAdd);
+
+            // Should never happen.
+            if (newSessionsCounter < 0)
+            {
+                throw new InvalidOperationException("Sessions counter is negative!");
+            }
+
+            // Clean record if user has no more active sessions.
+            if (newSessionsCounter == 0)
+            {
+                _activeUsers.TryRemove(new KeyValuePair<Guid, int>(userId, newSessionsCounter));
+            }
+        }
     }
 }

+ 50 - 3
Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessHandler.cs

@@ -3,6 +3,7 @@ using Jellyfin.Api.Helpers;
 using Jellyfin.Data.Enums;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.SyncPlay;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
 
@@ -13,20 +14,24 @@ namespace Jellyfin.Api.Auth.SyncPlayAccessPolicy
     /// </summary>
     public class SyncPlayAccessHandler : BaseAuthorizationHandler<SyncPlayAccessRequirement>
     {
+        private readonly ISyncPlayManager _syncPlayManager;
         private readonly IUserManager _userManager;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SyncPlayAccessHandler"/> class.
         /// </summary>
+        /// <param name="syncPlayManager">Instance of the <see cref="ISyncPlayManager"/> interface.</param>
         /// <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(
+            ISyncPlayManager syncPlayManager,
             IUserManager userManager,
             INetworkManager networkManager,
             IHttpContextAccessor httpContextAccessor)
             : base(userManager, networkManager, httpContextAccessor)
         {
+            _syncPlayManager = syncPlayManager;
             _userManager = userManager;
         }
 
@@ -42,10 +47,52 @@ namespace Jellyfin.Api.Auth.SyncPlayAccessPolicy
             var userId = ClaimHelpers.GetUserId(context.User);
             var user = _userManager.GetUserById(userId!.Value);
 
-            if ((requirement.RequiredAccess.HasValue && user.SyncPlayAccess == requirement.RequiredAccess)
-                || user.SyncPlayAccess == SyncPlayAccess.CreateAndJoinGroups)
+            if (requirement.RequiredAccess == SyncPlayAccessRequirementType.HasAccess)
             {
-                context.Succeed(requirement);
+                if (user.SyncPlayAccess == SyncPlayUserAccessType.CreateAndJoinGroups ||
+                    user.SyncPlayAccess == SyncPlayUserAccessType.JoinGroups ||
+                    _syncPlayManager.IsUserActive(userId!.Value))
+                {
+                    context.Succeed(requirement);
+                }
+                else
+                {
+                    context.Fail();
+                }
+            }
+            else if (requirement.RequiredAccess == SyncPlayAccessRequirementType.CreateGroup)
+            {
+                if (user.SyncPlayAccess == SyncPlayUserAccessType.CreateAndJoinGroups)
+                {
+                    context.Succeed(requirement);
+                }
+                else
+                {
+                    context.Fail();
+                }
+            }
+            else if (requirement.RequiredAccess == SyncPlayAccessRequirementType.JoinGroup)
+            {
+                if (user.SyncPlayAccess == SyncPlayUserAccessType.CreateAndJoinGroups ||
+                    user.SyncPlayAccess == SyncPlayUserAccessType.JoinGroups)
+                {
+                    context.Succeed(requirement);
+                }
+                else
+                {
+                    context.Fail();
+                }
+            }
+            else if (requirement.RequiredAccess == SyncPlayAccessRequirementType.IsInGroup)
+            {
+                if (_syncPlayManager.IsUserActive(userId!.Value))
+                {
+                    context.Succeed(requirement);
+                }
+                else
+                {
+                    context.Fail();
+                }
             }
             else
             {

+ 3 - 11
Jellyfin.Api/Auth/SyncPlayAccessPolicy/SyncPlayAccessRequirement.cs

@@ -11,23 +11,15 @@ namespace Jellyfin.Api.Auth.SyncPlayAccessPolicy
         /// <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)
+        /// <param name="requiredAccess">A value of <see cref="SyncPlayAccessRequirementType"/>.</param>
+        public SyncPlayAccessRequirement(SyncPlayAccessRequirementType 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; }
+        public SyncPlayAccessRequirementType RequiredAccess { get; }
     }
 }

+ 14 - 4
Jellyfin.Api/Constants/Policies.cs

@@ -51,13 +51,23 @@ namespace Jellyfin.Api.Constants
         public const string FirstTimeSetupOrIgnoreParentalControl = "FirstTimeSetupOrIgnoreParentalControl";
 
         /// <summary>
-        /// Policy name for requiring access to SyncPlay.
+        /// Policy name for accessing SyncPlay.
         /// </summary>
-        public const string SyncPlayAccess = "SyncPlayAccess";
+        public const string SyncPlayHasAccess = "SyncPlayHasAccess";
 
         /// <summary>
-        /// Policy name for requiring group creation access to SyncPlay.
+        /// Policy name for creating a SyncPlay group.
         /// </summary>
-        public const string SyncPlayCreateGroupAccess = "SyncPlayCreateGroupAccess";
+        public const string SyncPlayCreateGroup = "SyncPlayCreateGroup";
+
+        /// <summary>
+        /// Policy name for joining a SyncPlay group.
+        /// </summary>
+        public const string SyncPlayJoinGroup = "SyncPlayJoinGroup";
+
+        /// <summary>
+        /// Policy name for accessing a SyncPlay group.
+        /// </summary>
+        public const string SyncPlayIsInGroup = "SyncPlayIsInGroup";
     }
 }

+ 21 - 4
Jellyfin.Api/Controllers/SyncPlayController.cs

@@ -20,7 +20,7 @@ namespace Jellyfin.Api.Controllers
     /// <summary>
     /// The sync play controller.
     /// </summary>
-    [Authorize(Policy = Policies.SyncPlayAccess)]
+    [Authorize(Policy = Policies.SyncPlayHasAccess)]
     public class SyncPlayController : BaseJellyfinApiController
     {
         private readonly ISessionManager _sessionManager;
@@ -51,7 +51,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("New")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
-        [Authorize(Policy = Policies.SyncPlayCreateGroupAccess)]
+        [Authorize(Policy = Policies.SyncPlayCreateGroup)]
         public ActionResult SyncPlayCreateGroup(
             [FromBody, Required] NewGroupRequestDto requestData)
         {
@@ -69,7 +69,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Join")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
-        [Authorize(Policy = Policies.SyncPlayAccess)]
+        [Authorize(Policy = Policies.SyncPlayJoinGroup)]
         public ActionResult SyncPlayJoinGroup(
             [FromBody, Required] JoinGroupRequestDto requestData)
         {
@@ -86,6 +86,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Leave")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayLeaveGroup()
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
@@ -101,7 +102,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>An <see cref="IEnumerable{GroupInfoView}"/> containing the available SyncPlay groups.</returns>
         [HttpGet("List")]
         [ProducesResponseType(StatusCodes.Status200OK)]
-        [Authorize(Policy = Policies.SyncPlayAccess)]
+        [Authorize(Policy = Policies.SyncPlayJoinGroup)]
         public ActionResult<IEnumerable<GroupInfoDto>> SyncPlayGetGroups()
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
@@ -117,6 +118,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("SetNewQueue")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlaySetNewQueue(
             [FromBody, Required] PlayRequestDto requestData)
         {
@@ -137,6 +139,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("SetPlaylistItem")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlaySetPlaylistItem(
             [FromBody, Required] SetPlaylistItemRequestDto requestData)
         {
@@ -154,6 +157,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("RemoveFromPlaylist")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayRemoveFromPlaylist(
             [FromBody, Required] RemoveFromPlaylistRequestDto requestData)
         {
@@ -171,6 +175,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("MovePlaylistItem")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayMovePlaylistItem(
             [FromBody, Required] MovePlaylistItemRequestDto requestData)
         {
@@ -188,6 +193,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Queue")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayQueue(
             [FromBody, Required] QueueRequestDto requestData)
         {
@@ -204,6 +210,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Unpause")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayUnpause()
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
@@ -219,6 +226,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Pause")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayPause()
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
@@ -234,6 +242,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Stop")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayStop()
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authorizationContext, Request);
@@ -250,6 +259,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Seek")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlaySeek(
             [FromBody, Required] SeekRequestDto requestData)
         {
@@ -267,6 +277,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Buffering")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayBuffering(
             [FromBody, Required] BufferRequestDto requestData)
         {
@@ -288,6 +299,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("Ready")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayReady(
             [FromBody, Required] ReadyRequestDto requestData)
         {
@@ -309,6 +321,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("SetIgnoreWait")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlaySetIgnoreWait(
             [FromBody, Required] IgnoreWaitRequestDto requestData)
         {
@@ -326,6 +339,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("NextItem")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayNextItem(
             [FromBody, Required] NextItemRequestDto requestData)
         {
@@ -343,6 +357,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("PreviousItem")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlayPreviousItem(
             [FromBody, Required] PreviousItemRequestDto requestData)
         {
@@ -360,6 +375,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("SetRepeatMode")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlaySetRepeatMode(
             [FromBody, Required] SetRepeatModeRequestDto requestData)
         {
@@ -377,6 +393,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
         [HttpPost("SetShuffleMode")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [Authorize(Policy = Policies.SyncPlayIsInGroup)]
         public ActionResult SyncPlaySetShuffleMode(
             [FromBody, Required] SetShuffleModeRequestDto requestData)
         {

+ 2 - 2
Jellyfin.Data/Entities/User.cs

@@ -71,7 +71,7 @@ namespace Jellyfin.Data.Entities
             EnableAutoLogin = false;
             PlayDefaultAudioTrack = true;
             SubtitleMode = SubtitlePlaybackMode.Default;
-            SyncPlayAccess = SyncPlayAccess.CreateAndJoinGroups;
+            SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups;
 
             AddDefaultPermissions();
             AddDefaultPreferences();
@@ -326,7 +326,7 @@ namespace Jellyfin.Data.Entities
         /// <summary>
         /// Gets or sets the level of sync play permissions this user has.
         /// </summary>
-        public SyncPlayAccess SyncPlayAccess { get; set; }
+        public SyncPlayUserAccessType SyncPlayAccess { get; set; }
 
         /// <summary>
         /// Gets or sets the row version.

+ 28 - 0
Jellyfin.Data/Enums/SyncPlayAccessRequirementType.cs

@@ -0,0 +1,28 @@
+namespace Jellyfin.Data.Enums
+{
+    /// <summary>
+    /// Enum SyncPlayAccessRequirementType.
+    /// </summary>
+    public enum SyncPlayAccessRequirementType
+    {
+        /// <summary>
+        /// User must have access to SyncPlay, in some form.
+        /// </summary>
+        HasAccess = 0,
+
+        /// <summary>
+        /// User must be able to create groups.
+        /// </summary>
+        CreateGroup = 1,
+
+        /// <summary>
+        /// User must be able to join groups.
+        /// </summary>
+        JoinGroup = 2,
+
+        /// <summary>
+        /// User must be in a group.
+        /// </summary>
+        IsInGroup = 3
+    }
+}

+ 2 - 2
Jellyfin.Data/Enums/SyncPlayAccess.cs → Jellyfin.Data/Enums/SyncPlayUserAccessType.cs

@@ -1,9 +1,9 @@
 namespace Jellyfin.Data.Enums
 {
     /// <summary>
-    /// Enum SyncPlayAccess.
+    /// Enum SyncPlayUserAccessType.
     /// </summary>
-    public enum SyncPlayAccess
+    public enum SyncPlayUserAccessType
     {
         /// <summary>
         /// User can create groups and join them.

+ 18 - 4
Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs

@@ -127,18 +127,32 @@ namespace Jellyfin.Server.Extensions
                         policy.AddRequirements(new RequiresElevationRequirement());
                     });
                 options.AddPolicy(
-                    Policies.SyncPlayAccess,
+                    Policies.SyncPlayHasAccess,
                     policy =>
                     {
                         policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
-                        policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccess.JoinGroups));
+                        policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.HasAccess));
                     });
                 options.AddPolicy(
-                    Policies.SyncPlayCreateGroupAccess,
+                    Policies.SyncPlayCreateGroup,
                     policy =>
                     {
                         policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication);
-                        policy.AddRequirements(new SyncPlayAccessRequirement(SyncPlayAccess.CreateAndJoinGroups));
+                        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));
                     });
             });
         }

+ 7 - 0
MediaBrowser.Controller/SyncPlay/ISyncPlayManager.cs

@@ -51,5 +51,12 @@ namespace MediaBrowser.Controller.SyncPlay
         /// <param name="request">The request.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         void HandleRequest(SessionInfo session, IGroupPlaybackRequest request, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Checks whether a user has an active session using SyncPlay.
+        /// </summary>
+        /// <param name="userId">The user identifier to check.</param>
+        /// <returns><c>true</c> if the user is using SyncPlay; <c>false</c> otherwise.</returns>
+        bool IsUserActive(Guid userId);
     }
 }

+ 2 - 2
MediaBrowser.Model/Users/UserPolicy.cs

@@ -111,7 +111,7 @@ namespace MediaBrowser.Model.Users
         /// Gets or sets a value indicating what SyncPlay features the user can access.
         /// </summary>
         /// <value>Access level to SyncPlay features.</value>
-        public SyncPlayAccess SyncPlayAccess { get; set; }
+        public SyncPlayUserAccessType SyncPlayAccess { get; set; }
 
         public UserPolicy()
         {
@@ -160,7 +160,7 @@ namespace MediaBrowser.Model.Users
             EnableContentDownloading = true;
             EnablePublicSharing = true;
             EnableRemoteAccess = true;
-            SyncPlayAccess = SyncPlayAccess.CreateAndJoinGroups;
+            SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups;
         }
     }
 }