浏览代码

Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser

Michalis Adamidis 10 年之前
父节点
当前提交
671d302a92

+ 8 - 24
MediaBrowser.Api/ConnectService.cs

@@ -1,19 +1,12 @@
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Connect;
+using MediaBrowser.Controller.Connect;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using ServiceStack;
 using ServiceStack;
+using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Api
 namespace MediaBrowser.Api
 {
 {
-    [Route("/Users/{Id}/Connect/Info", "GET", Summary = "Gets connect info for a user")]
-    public class GetConnectUserInfo : IReturn<ConnectUserLink>
-    {
-        [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string Id { get; set; }
-    }
-
     [Route("/Users/{Id}/Connect/Link", "POST", Summary = "Creates a Connect link for a user")]
     [Route("/Users/{Id}/Connect/Link", "POST", Summary = "Creates a Connect link for a user")]
-    public class CreateConnectLink : IReturn<ConnectUserLink>
+    public class CreateConnectLink : IReturn<UserLinkResult>
     {
     {
         [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
         [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
         public string Id { get; set; }
         public string Id { get; set; }
@@ -23,13 +16,13 @@ namespace MediaBrowser.Api
     }
     }
 
 
     [Route("/Users/{Id}/Connect/Link", "DELETE", Summary = "Removes a Connect link for a user")]
     [Route("/Users/{Id}/Connect/Link", "DELETE", Summary = "Removes a Connect link for a user")]
-    public class DeleteConnectLink : IReturn<ConnectUserLink>
+    public class DeleteConnectLink : IReturnVoid
     {
     {
         [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
         [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
         public string Id { get; set; }
         public string Id { get; set; }
     }
     }
-    
-    [Authenticated]
+
+    [Authenticated(Roles = "Admin")]
     public class ConnectService : BaseApiService
     public class ConnectService : BaseApiService
     {
     {
         private readonly IConnectManager _connectManager;
         private readonly IConnectManager _connectManager;
@@ -39,18 +32,9 @@ namespace MediaBrowser.Api
             _connectManager = connectManager;
             _connectManager = connectManager;
         }
         }
 
 
-        public object Get(GetConnectUserInfo request)
+        public object Post(CreateConnectLink request)
         {
         {
-            var result = _connectManager.GetUserInfo(request.Id);
-
-            return ToOptimizedResult(result);
-        }
-
-        public void Post(CreateConnectLink request)
-        {
-            var task = _connectManager.LinkUser(request.Id, request.ConnectUsername);
-
-            Task.WaitAll(task);
+            return _connectManager.LinkUser(request.Id, request.ConnectUsername);
         }
         }
 
 
         public void Delete(DeleteConnectLink request)
         public void Delete(DeleteConnectLink request)

+ 0 - 20
MediaBrowser.Controller/Connect/ConnectInvitationRequest.cs

@@ -1,20 +0,0 @@
-
-namespace MediaBrowser.Controller.Connect
-{
-    public class ConnectInvitationRequest
-    {
-        public string LocalUserId { get; set; }
-
-        public string Username { get; set; }
-
-        public string RequesterUserId { get; set; }
-
-        public ConnectUserType Type { get; set; }
-    }
-
-    public enum ConnectUserType
-    {
-        LinkedUser = 1,
-        Guest = 2
-    }
-}

+ 2 - 6
MediaBrowser.Controller/Connect/ConnectUser.cs

@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
+
 namespace MediaBrowser.Controller.Connect
 namespace MediaBrowser.Controller.Connect
 {
 {
     public class ConnectUser
     public class ConnectUser
@@ -11,6 +6,7 @@ namespace MediaBrowser.Controller.Connect
         public string Id { get; set; }
         public string Id { get; set; }
         public string Name { get; set; }
         public string Name { get; set; }
         public string Email { get; set; }
         public string Email { get; set; }
+        public bool IsActive { get; set; }
     }
     }
 
 
     public class ConnectUserQuery
     public class ConnectUserQuery

+ 0 - 10
MediaBrowser.Controller/Connect/ConnectUserLink.cs

@@ -1,10 +0,0 @@
-
-namespace MediaBrowser.Controller.Connect
-{
-    public class ConnectUserLink
-    {
-        public string Username { get; set; }
-        public string UserId { get; set; }
-        public string LocalUserId { get; set; }
-    }
-}

+ 1 - 8
MediaBrowser.Controller/Connect/IConnectManager.cs

@@ -10,20 +10,13 @@ namespace MediaBrowser.Controller.Connect
         /// <value>The wan API address.</value>
         /// <value>The wan API address.</value>
         string WanApiAddress { get; }
         string WanApiAddress { get; }
 
 
-        /// <summary>
-        /// Gets the user information.
-        /// </summary>
-        /// <param name="userId">The user identifier.</param>
-        /// <returns>ConnectUserInfo.</returns>
-        ConnectUserLink GetUserInfo(string userId);
-
         /// <summary>
         /// <summary>
         /// Links the user.
         /// Links the user.
         /// </summary>
         /// </summary>
         /// <param name="userId">The user identifier.</param>
         /// <param name="userId">The user identifier.</param>
         /// <param name="connectUsername">The connect username.</param>
         /// <param name="connectUsername">The connect username.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
-        Task LinkUser(string userId, string connectUsername);
+        Task<UserLinkResult> LinkUser(string userId, string connectUsername);
 
 
         /// <summary>
         /// <summary>
         /// Removes the link.
         /// Removes the link.

+ 8 - 0
MediaBrowser.Controller/Connect/UserLinkResult.cs

@@ -0,0 +1,8 @@
+
+namespace MediaBrowser.Controller.Connect
+{
+    public class UserLinkResult
+    {
+        public bool IsPending { get; set; }
+    }
+}

+ 2 - 0
MediaBrowser.Controller/Entities/User.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Connect;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 using System;
 using System;
 using System.IO;
 using System.IO;
@@ -34,6 +35,7 @@ namespace MediaBrowser.Controller.Entities
 
 
         public string ConnectUserName { get; set; }
         public string ConnectUserName { get; set; }
         public string ConnectUserId { get; set; }
         public string ConnectUserId { get; set; }
+        public UserLinkType ConnectLinkType { get; set; }
         public string ConnectAccessKey { get; set; }
         public string ConnectAccessKey { get; set; }
 
 
         /// <summary>
         /// <summary>

+ 1 - 2
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -99,10 +99,9 @@
     <Compile Include="Collections\CollectionCreationOptions.cs" />
     <Compile Include="Collections\CollectionCreationOptions.cs" />
     <Compile Include="Collections\CollectionEvents.cs" />
     <Compile Include="Collections\CollectionEvents.cs" />
     <Compile Include="Collections\ICollectionManager.cs" />
     <Compile Include="Collections\ICollectionManager.cs" />
-    <Compile Include="Connect\ConnectInvitationRequest.cs" />
     <Compile Include="Connect\ConnectUser.cs" />
     <Compile Include="Connect\ConnectUser.cs" />
-    <Compile Include="Connect\ConnectUserLink.cs" />
     <Compile Include="Connect\IConnectManager.cs" />
     <Compile Include="Connect\IConnectManager.cs" />
+    <Compile Include="Connect\UserLinkResult.cs" />
     <Compile Include="Dlna\ControlRequest.cs" />
     <Compile Include="Dlna\ControlRequest.cs" />
     <Compile Include="Dlna\ControlResponse.cs" />
     <Compile Include="Dlna\ControlResponse.cs" />
     <Compile Include="Dlna\DlnaIconResponse.cs" />
     <Compile Include="Dlna\DlnaIconResponse.cs" />

+ 8 - 1
MediaBrowser.Controller/Net/AuthenticatedAttribute.cs

@@ -1,5 +1,6 @@
 using ServiceStack.Web;
 using ServiceStack.Web;
 using System;
 using System;
+using System.Linq;
 
 
 namespace MediaBrowser.Controller.Net
 namespace MediaBrowser.Controller.Net
 {
 {
@@ -13,6 +14,8 @@ namespace MediaBrowser.Controller.Net
         /// <value><c>true</c> if [allow local]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [allow local]; otherwise, <c>false</c>.</value>
         public bool AllowLocal { get; set; }
         public bool AllowLocal { get; set; }
 
 
+        public string Roles { get; set; }
+
         /// <summary>
         /// <summary>
         /// The request filter is executed before the service.
         /// The request filter is executed before the service.
         /// </summary>
         /// </summary>
@@ -21,7 +24,11 @@ namespace MediaBrowser.Controller.Net
         /// <param name="requestDto">The request DTO</param>
         /// <param name="requestDto">The request DTO</param>
         public void RequestFilter(IRequest request, IResponse response, object requestDto)
         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);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 6 - 1
MediaBrowser.Controller/Net/IAuthService.cs

@@ -1,9 +1,14 @@
 using ServiceStack.Web;
 using ServiceStack.Web;
+using System.Collections.Generic;
 
 
 namespace MediaBrowser.Controller.Net
 namespace MediaBrowser.Controller.Net
 {
 {
     public interface IAuthService
     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);
     }
     }
 }
 }

+ 3 - 0
MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj

@@ -188,6 +188,9 @@
     <Compile Include="..\MediaBrowser.Model\Configuration\XbmcMetadataOptions.cs">
     <Compile Include="..\MediaBrowser.Model\Configuration\XbmcMetadataOptions.cs">
       <Link>Configuration\XbmcMetadataOptions.cs</Link>
       <Link>Configuration\XbmcMetadataOptions.cs</Link>
     </Compile>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Connect\UserLinkType.cs">
+      <Link>Connect\UserLinkType.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\AudioOptions.cs">
     <Compile Include="..\MediaBrowser.Model\Dlna\AudioOptions.cs">
       <Link>Dlna\AudioOptions.cs</Link>
       <Link>Dlna\AudioOptions.cs</Link>
     </Compile>
     </Compile>

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

@@ -151,6 +151,9 @@
     <Compile Include="..\MediaBrowser.Model\Configuration\XbmcMetadataOptions.cs">
     <Compile Include="..\MediaBrowser.Model\Configuration\XbmcMetadataOptions.cs">
       <Link>Configuration\XbmcMetadataOptions.cs</Link>
       <Link>Configuration\XbmcMetadataOptions.cs</Link>
     </Compile>
     </Compile>
+    <Compile Include="..\mediabrowser.model\connect\UserLinkType.cs">
+      <Link>Connect\UserLinkType.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\AudioOptions.cs">
     <Compile Include="..\MediaBrowser.Model\Dlna\AudioOptions.cs">
       <Link>Dlna\AudioOptions.cs</Link>
       <Link>Dlna\AudioOptions.cs</Link>
     </Compile>
     </Compile>

+ 3 - 3
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -175,7 +175,7 @@ namespace MediaBrowser.Model.Configuration
 
 
         public PeopleMetadataOptions PeopleMetadataOptions { get; set; }
         public PeopleMetadataOptions PeopleMetadataOptions { get; set; }
 
 
-        public string[] SecureApps1 { get; set; }
+        public string[] SecureApps2 { get; set; }
 
 
         public bool SaveMetadataHidden { get; set; }
         public bool SaveMetadataHidden { get; set; }
 
 
@@ -223,7 +223,7 @@ namespace MediaBrowser.Model.Configuration
 
 
             PeopleMetadataOptions = new PeopleMetadataOptions();
             PeopleMetadataOptions = new PeopleMetadataOptions();
 
 
-            SecureApps1 = new[]
+            SecureApps2 = new[]
             {
             {
                 "Dashboard",
                 "Dashboard",
                 "MBKinect",
                 "MBKinect",
@@ -231,7 +231,7 @@ namespace MediaBrowser.Model.Configuration
                 "Media Browser Theater",
                 "Media Browser Theater",
 
 
                 //"Chrome Companion",
                 //"Chrome Companion",
-                //"MB-Classic"
+                "MB-Classic"
             };
             };
 
 
             MetadataOptions = new[]
             MetadataOptions = new[]

+ 15 - 0
MediaBrowser.Model/Connect/UserLinkType.cs

@@ -0,0 +1,15 @@
+
+namespace MediaBrowser.Model.Connect
+{
+    public enum UserLinkType
+    {
+        /// <summary>
+        /// The linked user
+        /// </summary>
+        LinkedUser = 1,
+        /// <summary>
+        /// The guest
+        /// </summary>
+        Guest = 2
+    }
+}

+ 18 - 1
MediaBrowser.Model/Dto/UserDto.cs

@@ -1,9 +1,10 @@
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Connect;
+using MediaBrowser.Model.Extensions;
 using System;
 using System;
 using System.ComponentModel;
 using System.ComponentModel;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Runtime.Serialization;
 using System.Runtime.Serialization;
-using MediaBrowser.Model.Extensions;
 
 
 namespace MediaBrowser.Model.Dto
 namespace MediaBrowser.Model.Dto
 {
 {
@@ -19,6 +20,22 @@ namespace MediaBrowser.Model.Dto
         /// <value>The name.</value>
         /// <value>The name.</value>
         public string Name { get; set; }
         public string Name { get; set; }
 
 
+        /// <summary>
+        /// Gets or sets the name of the connect user.
+        /// </summary>
+        /// <value>The name of the connect user.</value>
+        public string ConnectUserName { get; set; }
+        /// <summary>
+        /// Gets or sets the connect user identifier.
+        /// </summary>
+        /// <value>The connect user identifier.</value>
+        public string ConnectUserId { get; set; }
+        /// <summary>
+        /// Gets or sets the type of the connect link.
+        /// </summary>
+        /// <value>The type of the connect link.</value>
+        public UserLinkType ConnectLinkType { get; set; }
+        
         /// <summary>
         /// <summary>
         /// Gets or sets the id.
         /// Gets or sets the id.
         /// </summary>
         /// </summary>

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

@@ -81,6 +81,7 @@
     <Compile Include="Configuration\ChapterOptions.cs" />
     <Compile Include="Configuration\ChapterOptions.cs" />
     <Compile Include="Configuration\XbmcMetadataOptions.cs" />
     <Compile Include="Configuration\XbmcMetadataOptions.cs" />
     <Compile Include="Configuration\SubtitlePlaybackMode.cs" />
     <Compile Include="Configuration\SubtitlePlaybackMode.cs" />
+    <Compile Include="Connect\UserLinkType.cs" />
     <Compile Include="Drawing\ImageOrientation.cs" />
     <Compile Include="Drawing\ImageOrientation.cs" />
     <Compile Include="Dto\StreamOptions.cs" />
     <Compile Include="Dto\StreamOptions.cs" />
     <Compile Include="FileOrganization\AutoOrganizeOptions.cs" />
     <Compile Include="FileOrganization\AutoOrganizeOptions.cs" />

+ 56 - 41
MediaBrowser.Server.Implementations/Connect/ConnectManager.cs

@@ -6,6 +6,7 @@ using MediaBrowser.Controller.Connect;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Security;
 using MediaBrowser.Controller.Security;
+using MediaBrowser.Model.Connect;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
@@ -261,24 +262,12 @@ namespace MediaBrowser.Server.Implementations.Connect
             return user;
             return user;
         }
         }
 
 
-        public ConnectUserLink GetUserInfo(string userId)
-        {
-            var user = GetUser(userId);
-
-            return new ConnectUserLink
-            {
-                LocalUserId = user.Id.ToString("N"),
-                Username = user.ConnectUserName,
-                UserId = user.ConnectUserId
-            };
-        }
-
         private string GetConnectUrl(string handler)
         private string GetConnectUrl(string handler)
         {
         {
             return "https://connect.mediabrowser.tv/service/" + handler;
             return "https://connect.mediabrowser.tv/service/" + handler;
         }
         }
 
 
-        public async Task LinkUser(string userId, string connectUsername)
+        public async Task<UserLinkResult> LinkUser(string userId, string connectUsername)
         {
         {
             if (string.IsNullOrWhiteSpace(connectUsername))
             if (string.IsNullOrWhiteSpace(connectUsername))
             {
             {
@@ -291,11 +280,16 @@ namespace MediaBrowser.Server.Implementations.Connect
 
 
             }, CancellationToken.None).ConfigureAwait(false);
             }, CancellationToken.None).ConfigureAwait(false);
 
 
+            if (!connectUser.IsActive)
+            {
+                throw new ArgumentException("The Media Browser account has been disabled.");
+            }
+
             var user = GetUser(userId);
             var user = GetUser(userId);
 
 
             if (!string.IsNullOrWhiteSpace(user.ConnectUserId))
             if (!string.IsNullOrWhiteSpace(user.ConnectUserId))
             {
             {
-                await RemoveLink(user, connectUser).ConfigureAwait(false);
+                await RemoveLink(user, connectUser.Id).ConfigureAwait(false);
             }
             }
 
 
             var url = GetConnectUrl("ServerAuthorizations");
             var url = GetConnectUrl("ServerAuthorizations");
@@ -320,59 +314,79 @@ namespace MediaBrowser.Server.Implementations.Connect
 
 
             SetServerAccessToken(options);
             SetServerAccessToken(options);
 
 
+            var result = new UserLinkResult();
+
             // No need to examine the response
             // No need to examine the response
             using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
             using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
             {
             {
+                var response = _json.DeserializeFromStream<ServerUserAuthorizationResponse>(stream);
+
+                result.IsPending = string.Equals(response.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase);
             }
             }
 
 
             user.ConnectAccessKey = accessToken;
             user.ConnectAccessKey = accessToken;
             user.ConnectUserName = connectUser.Name;
             user.ConnectUserName = connectUser.Name;
             user.ConnectUserId = connectUser.Id;
             user.ConnectUserId = connectUser.Id;
+            user.ConnectLinkType = UserLinkType.LinkedUser;
 
 
             await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
             await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+
+            return result;
         }
         }
 
 
-        public async Task RemoveLink(string userId)
+        public Task RemoveLink(string userId)
         {
         {
             var user = GetUser(userId);
             var user = GetUser(userId);
 
 
-            var connectUser = await GetConnectUser(new ConnectUserQuery
-            {
-                Name = user.ConnectUserId
-
-            }, CancellationToken.None).ConfigureAwait(false);
-
-            await RemoveLink(user, connectUser).ConfigureAwait(false);
+            return RemoveLink(user, user.ConnectUserId);
         }
         }
 
 
-        public async Task RemoveLink(User user, ConnectUser connectUser)
+        private async Task RemoveLink(User user, string connectUserId)
         {
         {
-            var url = GetConnectUrl("ServerAuthorizations");
-
-            var options = new HttpRequestOptions
+            if (!string.IsNullOrWhiteSpace(connectUserId))
             {
             {
-                Url = url,
-                CancellationToken = CancellationToken.None
-            };
+                var url = GetConnectUrl("ServerAuthorizations");
 
 
-            var postData = new Dictionary<string, string>
-            {
-                {"serverId", ConnectServerId},
-                {"userId", connectUser.Id}
-            };
+                var options = new HttpRequestOptions
+                {
+                    Url = url,
+                    CancellationToken = CancellationToken.None
+                };
 
 
-            options.SetPostData(postData);
+                var postData = new Dictionary<string, string>
+                {
+                    {"serverId", ConnectServerId},
+                    {"userId", connectUserId}
+                };
 
 
-            SetServerAccessToken(options);
+                options.SetPostData(postData);
 
 
-            // No need to examine the response
-            using (var stream = (await _httpClient.SendAsync(options, "DELETE").ConfigureAwait(false)).Content)
-            {
+                SetServerAccessToken(options);
+
+                try
+                {
+                    // No need to examine the response
+                    using (var stream = (await _httpClient.SendAsync(options, "DELETE").ConfigureAwait(false)).Content)
+                    {
+                    }
+                }
+                catch (HttpException ex)
+                {
+                    // If connect says the auth doesn't exist, we can handle that gracefully since this is a remove operation
+
+                    if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound)
+                    {
+                        throw;
+                    }
+
+                    _logger.Debug("Connect returned a 404 when removing a user auth link. Handling it.");
+                }
             }
             }
-            
+
             user.ConnectAccessKey = null;
             user.ConnectAccessKey = null;
             user.ConnectUserName = null;
             user.ConnectUserName = null;
             user.ConnectUserId = null;
             user.ConnectUserId = null;
+            user.ConnectLinkType = UserLinkType.LinkedUser;
 
 
             await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
             await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
         }
         }
@@ -410,7 +424,8 @@ namespace MediaBrowser.Server.Implementations.Connect
                 {
                 {
                     Email = response.Email,
                     Email = response.Email,
                     Id = response.Id,
                     Id = response.Id,
-                    Name = response.Name
+                    Name = response.Name,
+                    IsActive = response.IsActive
                 };
                 };
             }
             }
         }
         }

+ 13 - 1
MediaBrowser.Server.Implementations/Connect/Responses.cs

@@ -22,7 +22,19 @@ namespace MediaBrowser.Server.Implementations.Connect
         public string Name { get; set; }
         public string Name { get; set; }
         public string DisplayName { get; set; }
         public string DisplayName { get; set; }
         public string Email { get; set; }
         public string Email { get; set; }
-        public string IsActive { get; set; }
+        public bool IsActive { get; set; }
         public string ImageUrl { get; set; }
         public string ImageUrl { get; set; }
     }
     }
+
+    public class ServerUserAuthorizationResponse
+    {
+        public string Id { get; set; }
+        public string ServerId { get; set; }
+        public string UserId { get; set; }
+        public string AccessToken { get; set; }
+        public string DateCreated { get; set; }
+        public bool IsActive { get; set; }
+        public string AcceptStatus { get; set; }
+        public string UserType { get; set; }
+    }
 }
 }

+ 20 - 9
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.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
@@ -42,24 +41,29 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
         /// </summary>
         /// </summary>
         public string HtmlRedirect { get; set; }
         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;
                 return;
 
 
             //ExecuteBasic(req, res, requestDto); //first check if session is authenticated
             //ExecuteBasic(req, res, requestDto); //first check if session is authenticated
             //if (res.IsClosed) return; //AuthenticateAttribute already closed the request (ie auth failed)
             //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
             //This code is executed before the service
             var auth = AuthorizationContext.GetAuthorizationInfo(req);
             var auth = AuthorizationContext.GetAuthorizationInfo(req);
 
 
             if (!string.IsNullOrWhiteSpace(auth.Token)
             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)
                 if (!allowLocal || !req.IsLocal)
                 {
                 {
@@ -73,8 +77,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
 
 
             if (user == null & !string.IsNullOrWhiteSpace(auth.UserId))
             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)
             if (user != null && user.Configuration.IsDisabled)
@@ -82,6 +85,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
                 throw new AuthenticationException("User account has been disabled.");
                 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) &&
             if (!string.IsNullOrWhiteSpace(auth.DeviceId) &&
                 !string.IsNullOrWhiteSpace(auth.Client) &&
                 !string.IsNullOrWhiteSpace(auth.Client) &&
                 !string.IsNullOrWhiteSpace(auth.Device))
                 !string.IsNullOrWhiteSpace(auth.Device))

+ 6 - 3
MediaBrowser.Server.Implementations/Library/UserManager.cs

@@ -86,7 +86,7 @@ namespace MediaBrowser.Server.Implementations.Library
         /// </summary>
         /// </summary>
         public event EventHandler<GenericEventArgs<User>> UserUpdated;
         public event EventHandler<GenericEventArgs<User>> UserUpdated;
         public event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated;
         public event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated;
-        
+
         /// <summary>
         /// <summary>
         /// Called when [user updated].
         /// Called when [user updated].
         /// </summary>
         /// </summary>
@@ -137,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Library
         {
         {
             return GetUserById(new Guid(id));
             return GetUserById(new Guid(id));
         }
         }
-        
+
         public async Task Initialize()
         public async Task Initialize()
         {
         {
             Users = await LoadUsers().ConfigureAwait(false);
             Users = await LoadUsers().ConfigureAwait(false);
@@ -260,7 +260,10 @@ namespace MediaBrowser.Server.Implementations.Library
                 HasConfiguredPassword = hasConfiguredDefaultPassword,
                 HasConfiguredPassword = hasConfiguredDefaultPassword,
                 LastActivityDate = user.LastActivityDate,
                 LastActivityDate = user.LastActivityDate,
                 LastLoginDate = user.LastLoginDate,
                 LastLoginDate = user.LastLoginDate,
-                Configuration = user.Configuration
+                Configuration = user.Configuration,
+                ConnectLinkType = user.ConnectLinkType,
+                ConnectUserId = user.ConnectUserId,
+                ConnectUserName = user.ConnectUserName
             };
             };
 
 
             var image = user.GetImageInfo(ImageType.Primary, 0);
             var image = user.GetImageInfo(ImageType.Primary, 0);

+ 5 - 1
MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json

@@ -453,5 +453,9 @@
     "MessageYouHaveAnActiveRecurringMembership": "You have an active {0} membership. You can upgrade your plan using the options below.",
     "MessageYouHaveAnActiveRecurringMembership": "You have an active {0} membership. You can upgrade your plan using the options below.",
     "ButtonDelete": "Delete",
     "ButtonDelete": "Delete",
     "HeaderMediaBrowserAccountAdded": "Media Browser Account Added",
     "HeaderMediaBrowserAccountAdded": "Media Browser Account Added",
-    "MessageMediaBrowserAccontAdded": "A Media Browser account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email."
+    "MessageMediaBrowserAccountAdded": "The Media Browser account has been added to this user.",
+    "MessagePendingMediaBrowserAccountAdded": "The Media Browser account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.",
+    "HeaderMediaBrowserAccountRemoved": "Media Browser Account Removed",
+    "MessageMediaBrowserAccontRemoved": "The Media Browser account has been removed from this user.",
+    "TooltipLinkedToMediaBrowserConnect": "Linked to Media Browser Connect"
 }
 }

+ 3 - 1
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -684,6 +684,7 @@
     "OptionPlainVideoItemsHelp": "If enabled, all videos are represented in DIDL as \"object.item.videoItem\" instead of a more specific type, such as \"object.item.videoItem.movie\".",
     "OptionPlainVideoItemsHelp": "If enabled, all videos are represented in DIDL as \"object.item.videoItem\" instead of a more specific type, such as \"object.item.videoItem.movie\".",
     "LabelSupportedMediaTypes": "Supported Media Types:",
     "LabelSupportedMediaTypes": "Supported Media Types:",
     "TabIdentification": "Identification",
     "TabIdentification": "Identification",
+    "HeaderIdentification": "Identification",
     "TabDirectPlay": "Direct Play",
     "TabDirectPlay": "Direct Play",
     "TabContainers": "Containers",
     "TabContainers": "Containers",
     "TabCodecs": "Codecs",
     "TabCodecs": "Codecs",
@@ -1160,5 +1161,6 @@
     "LabelExtractChaptersDuringLibraryScan": "Extract chapter images during the library scan",
     "LabelExtractChaptersDuringLibraryScan": "Extract chapter images during the library scan",
     "LabelExtractChaptersDuringLibraryScanHelp": "If enabled, chapter images will be extracted when videos are imported during the library scan. If disabled they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.",
     "LabelExtractChaptersDuringLibraryScanHelp": "If enabled, chapter images will be extracted when videos are imported during the library scan. If disabled they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.",
     "LabelConnectUserName": "Media Browser username/email:",
     "LabelConnectUserName": "Media Browser username/email:",
-    "LabelConnectUserNameHelp": "Connect this user to a Media Browser account to enable easy sign-in access from any app without having to know the server ip address."
+    "LabelConnectUserNameHelp": "Connect this user to a Media Browser account to enable easy sign-in access from any app without having to know the server ip address.",
+    "ButtonLearnMoreAboutMediaBrowserConnect": "Learn more about Media Browser Connect"
 }
 }