ソースを参照

added some user access settings

Luke Pulverenti 12 年 前
コミット
56eea6a626

+ 74 - 6
MediaBrowser.Api/UserService.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Users;
 using ServiceStack.ServiceHost;
 using ServiceStack.ServiceHost;
 using ServiceStack.Text.Controller;
 using ServiceStack.Text.Controller;
 using System;
 using System;
@@ -19,6 +20,11 @@ namespace MediaBrowser.Api
     [Api(Description = "Gets a list of users")]
     [Api(Description = "Gets a list of users")]
     public class GetUsers : IReturn<List<UserDto>>
     public class GetUsers : IReturn<List<UserDto>>
     {
     {
+        [ApiMember(Name = "IsHidden", Description="Optional filter by IsHidden=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? IsHidden { get; set; }
+
+        [ApiMember(Name = "IsDisabled", Description = "Optional filter by IsDisabled=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? IsDisabled { get; set; }
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -56,7 +62,7 @@ namespace MediaBrowser.Api
     /// </summary>
     /// </summary>
     [Route("/Users/{Id}/Authenticate", "POST")]
     [Route("/Users/{Id}/Authenticate", "POST")]
     [Api(Description = "Authenticates a user")]
     [Api(Description = "Authenticates a user")]
-    public class AuthenticateUser : IReturnVoid
+    public class AuthenticateUser : IReturn<AuthenticationResult>
     {
     {
         /// <summary>
         /// <summary>
         /// Gets or sets the id.
         /// Gets or sets the id.
@@ -73,6 +79,28 @@ namespace MediaBrowser.Api
         public string Password { get; set; }
         public string Password { get; set; }
     }
     }
 
 
+    /// <summary>
+    /// Class AuthenticateUser
+    /// </summary>
+    [Route("/Users/{Name}/AuthenticateByName", "POST")]
+    [Api(Description = "Authenticates a user")]
+    public class AuthenticateUserByName : IReturn<AuthenticationResult>
+    {
+        /// <summary>
+        /// Gets or sets the id.
+        /// </summary>
+        /// <value>The id.</value>
+        [ApiMember(Name = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets the password.
+        /// </summary>
+        /// <value>The password.</value>
+        [ApiMember(Name = "Password", IsRequired = true, DataType = "string", ParameterType = "body", Verb = "POST")]
+        public string Password { get; set; }
+    }
+
     /// <summary>
     /// <summary>
     /// Class UpdateUserPassword
     /// Class UpdateUserPassword
     /// </summary>
     /// </summary>
@@ -168,11 +196,21 @@ namespace MediaBrowser.Api
         {
         {
             var dtoBuilder = new UserDtoBuilder(Logger);
             var dtoBuilder = new UserDtoBuilder(Logger);
 
 
-            var tasks = _userManager.Users.OrderBy(u => u.Name).Select(dtoBuilder.GetUserDto);
+            var users = _userManager.Users;
+
+            if (request.IsDisabled.HasValue)
+            {
+                users = users.Where(i => i.Configuration.IsDisabled == request.IsDisabled.Value);
+            }
+
+            if (request.IsHidden.HasValue)
+            {
+                users = users.Where(i => i.Configuration.IsHidden == request.IsHidden.Value);
+            }
 
 
-            var users = tasks.Select(i => i.Result).ToList();
+            var tasks = users.OrderBy(u => u.Name).Select(dtoBuilder.GetUserDto).Select(i => i.Result);
 
 
-            return ToOptimizedResult(users);
+            return ToOptimizedResult(tasks.ToList());
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -218,7 +256,21 @@ namespace MediaBrowser.Api
         /// Posts the specified request.
         /// Posts the specified request.
         /// </summary>
         /// </summary>
         /// <param name="request">The request.</param>
         /// <param name="request">The request.</param>
-        public void Post(AuthenticateUser request)
+        public object Post(AuthenticateUser request)
+        {
+            var result = AuthenticateUser(request).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Post(AuthenticateUserByName request)
+        {
+            var user = _userManager.Users.FirstOrDefault(i => string.Equals(request.Name, i.Name, StringComparison.OrdinalIgnoreCase));
+
+            return AuthenticateUser(new AuthenticateUser { Id = user.Id, Password = request.Password }).Result;
+        }
+
+        private async Task<object> AuthenticateUser(AuthenticateUser request)
         {
         {
             var user = _userManager.GetUserById(request.Id);
             var user = _userManager.GetUserById(request.Id);
 
 
@@ -227,13 +279,20 @@ namespace MediaBrowser.Api
                 throw new ResourceNotFoundException("User not found");
                 throw new ResourceNotFoundException("User not found");
             }
             }
 
 
-            var success = _userManager.AuthenticateUser(user, request.Password).Result;
+            var success = await _userManager.AuthenticateUser(user, request.Password).ConfigureAwait(false);
 
 
             if (!success)
             if (!success)
             {
             {
                 // Unauthorized
                 // Unauthorized
                 throw new UnauthorizedAccessException("Invalid user or password entered.");
                 throw new UnauthorizedAccessException("Invalid user or password entered.");
             }
             }
+
+            var result = new AuthenticationResult
+            {
+                User = await new UserDtoBuilder(Logger).GetUserDto(user).ConfigureAwait(false)
+            };
+
+            return ToOptimizedResult(result);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -294,6 +353,15 @@ namespace MediaBrowser.Api
                 }
                 }
             }
             }
 
 
+            // If removing admin access
+            if (dtoUser.Configuration.IsDisabled && !user.Configuration.IsDisabled)
+            {
+                if (_userManager.Users.Count(i => !i.Configuration.IsDisabled) == 1)
+                {
+                    throw new ArgumentException("There must be at least one enabled user in the system.");
+                }
+            }
+
             var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ? _userManager.UpdateUser(user) : _userManager.RenameUser(user, dtoUser.Name);
             var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ? _userManager.UpdateUser(user) : _userManager.RenameUser(user, dtoUser.Name);
 
 
             Task.WaitAll(task);
             Task.WaitAll(task);

+ 6 - 0
MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj

@@ -52,6 +52,9 @@
     <Compile Include="..\MediaBrowser.Model\Configuration\BaseApplicationConfiguration.cs">
     <Compile Include="..\MediaBrowser.Model\Configuration\BaseApplicationConfiguration.cs">
       <Link>Configuration\BaseApplicationConfiguration.cs</Link>
       <Link>Configuration\BaseApplicationConfiguration.cs</Link>
     </Compile>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Configuration\ManualLoginCategory.cs">
+      <Link>Configuration\ManualLoginCategory.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Configuration\ServerConfiguration.cs">
     <Compile Include="..\MediaBrowser.Model\Configuration\ServerConfiguration.cs">
       <Link>Configuration\ServerConfiguration.cs</Link>
       <Link>Configuration\ServerConfiguration.cs</Link>
     </Compile>
     </Compile>
@@ -331,6 +334,9 @@
     <Compile Include="..\MediaBrowser.Model\Updates\PackageVersionInfo.cs">
     <Compile Include="..\MediaBrowser.Model\Updates\PackageVersionInfo.cs">
       <Link>Updates\PackageVersionInfo.cs</Link>
       <Link>Updates\PackageVersionInfo.cs</Link>
     </Compile>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Users\AuthenticationResult.cs">
+      <Link>Users\AuthenticationResult.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Weather\WeatherUnits.cs">
     <Compile Include="..\MediaBrowser.Model\Weather\WeatherUnits.cs">
       <Link>Weather\WeatherUnits.cs</Link>
       <Link>Weather\WeatherUnits.cs</Link>
     </Compile>
     </Compile>

+ 10 - 0
MediaBrowser.Model/Configuration/ManualLoginCategory.cs

@@ -0,0 +1,10 @@
+
+namespace MediaBrowser.Model.Configuration
+{
+    public enum ManualLoginCategory
+    {
+        Mobile,
+        MediaBrowserTheater,
+        Roku
+    }
+}

+ 6 - 2
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -1,6 +1,6 @@
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using System;
 using MediaBrowser.Model.Weather;
 using MediaBrowser.Model.Weather;
+using System;
 
 
 namespace MediaBrowser.Model.Configuration
 namespace MediaBrowser.Model.Configuration
 {
 {
@@ -20,7 +20,7 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// </summary>
         /// <value>The weather unit.</value>
         /// <value>The weather unit.</value>
         public WeatherUnits WeatherUnit { get; set; }
         public WeatherUnits WeatherUnit { get; set; }
-        
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [enable HTTP level logging].
         /// Gets or sets a value indicating whether [enable HTTP level logging].
         /// </summary>
         /// </summary>
@@ -223,6 +223,8 @@ namespace MediaBrowser.Model.Configuration
         /// <value>The dashboard source path.</value>
         /// <value>The dashboard source path.</value>
         public string DashboardSourcePath { get; set; }
         public string DashboardSourcePath { get; set; }
 
 
+        public ManualLoginCategory[] ManualLoginClients { get; set; }
+
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// </summary>
         /// </summary>
@@ -249,6 +251,8 @@ namespace MediaBrowser.Model.Configuration
             EnableInternetProviders = true; //initial installs will need these
             EnableInternetProviders = true; //initial installs will need these
             InternetProviderExcludeTypes = new string[] { };
             InternetProviderExcludeTypes = new string[] { };
 
 
+            ManualLoginClients = new ManualLoginCategory[] { };
+
             MetadataRefreshDays = 30;
             MetadataRefreshDays = 30;
             PreferredMetadataLanguage = "en";
             PreferredMetadataLanguage = "en";
             MetadataCountryCode = "US";
             MetadataCountryCode = "US";

+ 9 - 1
MediaBrowser.Model/Configuration/UserConfiguration.cs

@@ -47,7 +47,15 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [use forced subtitles only]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [use forced subtitles only]; otherwise, <c>false</c>.</value>
         public bool UseForcedSubtitlesOnly { get; set; }
         public bool UseForcedSubtitlesOnly { get; set; }
-        
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is hidden.
+        /// </summary>
+        /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value>
+        public bool IsHidden { get; set; }
+
+        public bool IsDisabled { get; set; }
+
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="UserConfiguration" /> class.
         /// Initializes a new instance of the <see cref="UserConfiguration" /> class.
         /// </summary>
         /// </summary>

+ 2 - 0
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -43,6 +43,7 @@
     </Compile>
     </Compile>
     <Compile Include="ApiClient\IApiClient.cs" />
     <Compile Include="ApiClient\IApiClient.cs" />
     <Compile Include="Configuration\BaseApplicationConfiguration.cs" />
     <Compile Include="Configuration\BaseApplicationConfiguration.cs" />
+    <Compile Include="Configuration\ManualLoginCategory.cs" />
     <Compile Include="Configuration\ServerConfiguration.cs" />
     <Compile Include="Configuration\ServerConfiguration.cs" />
     <Compile Include="Dto\BaseItemPerson.cs" />
     <Compile Include="Dto\BaseItemPerson.cs" />
     <Compile Include="Dto\ChapterInfoDto.cs" />
     <Compile Include="Dto\ChapterInfoDto.cs" />
@@ -141,6 +142,7 @@
     <Compile Include="Tasks\TaskTriggerInfo.cs" />
     <Compile Include="Tasks\TaskTriggerInfo.cs" />
     <Compile Include="Updates\PackageInfo.cs" />
     <Compile Include="Updates\PackageInfo.cs" />
     <Compile Include="Updates\PackageVersionInfo.cs" />
     <Compile Include="Updates\PackageVersionInfo.cs" />
+    <Compile Include="Users\AuthenticationResult.cs" />
     <Compile Include="Weather\WeatherUnits.cs" />
     <Compile Include="Weather\WeatherUnits.cs" />
     <Compile Include="Web\QueryStringDictionary.cs" />
     <Compile Include="Web\QueryStringDictionary.cs" />
     <None Include="FodyWeavers.xml" />
     <None Include="FodyWeavers.xml" />

+ 9 - 0
MediaBrowser.Model/Users/AuthenticationResult.cs

@@ -0,0 +1,9 @@
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Model.Users
+{
+    public class AuthenticationResult
+    {
+        public UserDto User { get; set; }
+    }
+}

+ 7 - 5
MediaBrowser.Server.Implementations/Library/UserManager.cs

@@ -1,10 +1,7 @@
-using System.IO;
-using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
@@ -12,12 +9,12 @@ using MediaBrowser.Model.Logging;
 using System;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Security.Cryptography;
 using System.Security.Cryptography;
 using System.Text;
 using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Session;
 
 
 namespace MediaBrowser.Server.Implementations.Library
 namespace MediaBrowser.Server.Implementations.Library
 {
 {
@@ -174,6 +171,11 @@ namespace MediaBrowser.Server.Implementations.Library
                 throw new ArgumentNullException("user");
                 throw new ArgumentNullException("user");
             }
             }
 
 
+            if (user.Configuration.IsDisabled)
+            {
+                throw new UnauthorizedAccessException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
+            }
+
             var existingPasswordString = string.IsNullOrEmpty(user.Password) ? GetSha1String(string.Empty) : user.Password;
             var existingPasswordString = string.IsNullOrEmpty(user.Password) ? GetSha1String(string.Empty) : user.Password;
 
 
             var success = string.Equals(existingPasswordString, password.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
             var success = string.Equals(existingPasswordString, password.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);

+ 5 - 0
MediaBrowser.Server.Implementations/Session/SessionManager.cs

@@ -101,6 +101,11 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <exception cref="System.ArgumentNullException">user</exception>
         /// <exception cref="System.ArgumentNullException">user</exception>
         public Task LogConnectionActivity(string clientType, string deviceId, string deviceName, User user)
         public Task LogConnectionActivity(string clientType, string deviceId, string deviceName, User user)
         {
         {
+            if (user != null && user.Configuration.IsDisabled)
+            {
+                throw new UnauthorizedAccessException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
+            }
+
             var activityDate = DateTime.UtcNow;
             var activityDate = DateTime.UtcNow;
 
 
             GetConnection(clientType, deviceId, deviceName, user).LastActivityDate = activityDate;
             GetConnection(clientType, deviceId, deviceName, user).LastActivityDate = activityDate;

+ 16 - 2
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -5,7 +5,6 @@ using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
@@ -221,7 +220,21 @@ namespace MediaBrowser.WebDashboard.Api
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetDashboardConfigurationPages request)
         public object Get(GetDashboardConfigurationPages request)
         {
         {
-            var pages = ServerEntryPoint.Instance.PluginConfigurationPages;
+            const string unavilableMessage = "The server is still loading. Please try again momentarily.";
+
+            var instance = ServerEntryPoint.Instance;
+
+            if (instance == null)
+            {
+                throw new InvalidOperationException(unavilableMessage);
+            }
+
+            var pages = instance.PluginConfigurationPages;
+
+            if (pages == null)
+            {
+                throw new InvalidOperationException(unavilableMessage);
+            }
 
 
             if (request.PageType.HasValue)
             if (request.PageType.HasValue)
             {
             {
@@ -428,6 +441,7 @@ namespace MediaBrowser.WebDashboard.Api
                                       "librarybrowser.js",
                                       "librarybrowser.js",
 
 
                                       "aboutpage.js",
                                       "aboutpage.js",
+                                      "allusersettings.js",
                                       "alphapicker.js",
                                       "alphapicker.js",
                                       "addpluginpage.js",
                                       "addpluginpage.js",
                                       "advancedconfigurationpage.js",
                                       "advancedconfigurationpage.js",

+ 29 - 2
MediaBrowser.WebDashboard/ApiClient.js

@@ -1432,9 +1432,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
         /**
         /**
          * Gets all users from the server
          * Gets all users from the server
          */
          */
-        self.getUsers = function () {
+        self.getUsers = function (options) {
 
 
-            var url = self.getUrl("users");
+            var url = self.getUrl("users", options || {});
 
 
             return self.ajax({
             return self.ajax({
                 type: "GET",
                 type: "GET",
@@ -1870,6 +1870,32 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
             return files;
             return files;
         };
         };
 
 
+        /**
+         * Authenticates a user
+         * @param {String} name
+         * @param {String} password
+         */
+        self.authenticateUserByName = function (name, password) {
+
+            if (!name) {
+                throw new Error("null name");
+            }
+
+            var url = self.getUrl("Users/" + name + "/authenticatebyname");
+
+            var postData = {
+                password: MediaBrowser.SHA1(password || "")
+            };
+
+            return self.ajax({
+                type: "POST",
+                url: url,
+                data: JSON.stringify(postData),
+                dataType: "json",
+                contentType: "application/json"
+            });
+        };
+
         /**
         /**
          * Authenticates a user
          * Authenticates a user
          * @param {String} userId
          * @param {String} userId
@@ -1891,6 +1917,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
                 type: "POST",
                 type: "POST",
                 url: url,
                 url: url,
                 data: JSON.stringify(postData),
                 data: JSON.stringify(postData),
+                dataType: "json",
                 contentType: "application/json"
                 contentType: "application/json"
             });
             });
         };
         };

+ 6 - 0
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -81,6 +81,9 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="ApiClient.js" />
     <EmbeddedResource Include="ApiClient.js" />
+    <Content Include="dashboard-ui\allusersettings.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\boxsets.html">
     <Content Include="dashboard-ui\boxsets.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
@@ -354,6 +357,9 @@
     <Content Include="dashboard-ui\musicvideos.html">
     <Content Include="dashboard-ui\musicvideos.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
+    <Content Include="dashboard-ui\scripts\allusersettings.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\alphapicker.js">
     <Content Include="dashboard-ui\scripts\alphapicker.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>

+ 1 - 1
MediaBrowser.WebDashboard/packages.config

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
 <packages>
-  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.135" targetFramework="net45" />
+  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.138" targetFramework="net45" />
   <package id="ServiceStack.Common" version="3.9.54" targetFramework="net45" />
   <package id="ServiceStack.Common" version="3.9.54" targetFramework="net45" />
   <package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" />
   <package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" />
 </packages>
 </packages>