diff --git a/MediaBrowser.Api/ConnectService.cs b/MediaBrowser.Api/ConnectService.cs index 4d3cad49d7..e2a1b98e92 100644 --- a/MediaBrowser.Api/ConnectService.cs +++ b/MediaBrowser.Api/ConnectService.cs @@ -1,7 +1,7 @@ -using System.Threading.Tasks; -using MediaBrowser.Controller.Connect; +using MediaBrowser.Controller.Connect; using MediaBrowser.Controller.Net; using ServiceStack; +using System.Threading.Tasks; namespace MediaBrowser.Api { @@ -28,8 +28,8 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")] public string Id { get; set; } } - - [Authenticated] + + [Authenticated(Roles = "Admin")] public class ConnectService : BaseApiService { private readonly IConnectManager _connectManager; diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs index 329dbaa463..31bb7c66be 100644 --- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs +++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs @@ -1,5 +1,6 @@ using ServiceStack.Web; using System; +using System.Linq; namespace MediaBrowser.Controller.Net { @@ -13,6 +14,8 @@ namespace MediaBrowser.Controller.Net /// true if [allow local]; otherwise, false. public bool AllowLocal { get; set; } + public string Roles { get; set; } + /// /// The request filter is executed before the service. /// @@ -21,7 +24,11 @@ namespace MediaBrowser.Controller.Net /// The request DTO public void RequestFilter(IRequest request, IResponse response, object requestDto) { - AuthService.Authenticate(request, response, requestDto, AllowLocal); + var roles = (Roles ?? string.Empty).Split(',') + .Where(i => !string.IsNullOrWhiteSpace(i)) + .ToArray(); + + AuthService.Authenticate(request, response, requestDto, AllowLocal, roles); } /// diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs index dca70f58fe..69014d0ff1 100644 --- a/MediaBrowser.Controller/Net/IAuthService.cs +++ b/MediaBrowser.Controller/Net/IAuthService.cs @@ -1,9 +1,14 @@ using ServiceStack.Web; +using System.Collections.Generic; namespace MediaBrowser.Controller.Net { public interface IAuthService { - void Authenticate(IRequest request, IResponse response, object requestDto, bool allowLocal); + void Authenticate(IRequest request, + IResponse response, + object requestDto, + bool allowLocal, + string[] roles); } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 0fdb8f7cc3..4786194e27 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -175,7 +175,7 @@ namespace MediaBrowser.Model.Configuration public PeopleMetadataOptions PeopleMetadataOptions { get; set; } - public string[] SecureApps1 { get; set; } + public string[] SecureApps2 { get; set; } public bool SaveMetadataHidden { get; set; } @@ -223,7 +223,7 @@ namespace MediaBrowser.Model.Configuration PeopleMetadataOptions = new PeopleMetadataOptions(); - SecureApps1 = new[] + SecureApps2 = new[] { "Dashboard", "MBKinect", @@ -231,7 +231,7 @@ namespace MediaBrowser.Model.Configuration "Media Browser Theater", //"Chrome Companion", - //"MB-Classic" + "MB-Classic" }; MetadataOptions = new[] diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs index ea09824911..4b699c0184 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; @@ -42,24 +41,29 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security /// public string HtmlRedirect { get; set; } - public void Authenticate(IRequest req, IResponse res, object requestDto, bool allowLocal) + public void Authenticate(IRequest request, + IResponse response, + object requestDto, + bool allowLocal, + string[] roles) { - if (HostContext.HasValidAuthSecret(req)) + if (HostContext.HasValidAuthSecret(request)) return; //ExecuteBasic(req, res, requestDto); //first check if session is authenticated //if (res.IsClosed) return; //AuthenticateAttribute already closed the request (ie auth failed) - ValidateUser(req, allowLocal); + ValidateUser(request, allowLocal, roles); } - private void ValidateUser(IRequest req, bool allowLocal) + private void ValidateUser(IRequest req, bool allowLocal, + string[] roles) { //This code is executed before the service var auth = AuthorizationContext.GetAuthorizationInfo(req); if (!string.IsNullOrWhiteSpace(auth.Token) - || _config.Configuration.SecureApps1.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + || _config.Configuration.SecureApps2.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { if (!allowLocal || !req.IsLocal) { @@ -73,8 +77,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security if (user == null & !string.IsNullOrWhiteSpace(auth.UserId)) { - // TODO: Re-enable - //throw new ArgumentException("User with Id " + auth.UserId + " not found"); + throw new ArgumentException("User with Id " + auth.UserId + " not found"); } if (user != null && user.Configuration.IsDisabled) @@ -82,6 +85,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security throw new AuthenticationException("User account has been disabled."); } + if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) + { + if (user == null || !user.Configuration.IsAdministrator) + { + throw new ArgumentException("Administrative access is required for this request."); + } + } + if (!string.IsNullOrWhiteSpace(auth.DeviceId) && !string.IsNullOrWhiteSpace(auth.Client) && !string.IsNullOrWhiteSpace(auth.Device))