From ef6b90b8e6e6c317fcda85a392c79324f91250db Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 25 Oct 2016 15:02:04 -0400 Subject: make controller project portable --- .../HttpServer/Security/SessionContext.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs') diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs index a498d32fa..f51ca55a8 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs @@ -3,8 +3,8 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; -using ServiceStack.Web; using System.Threading.Tasks; +using MediaBrowser.Model.Services; namespace MediaBrowser.Server.Implementations.HttpServer.Security { @@ -47,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security public Task GetSession(object requestContext) { - var req = new ServiceStackServiceRequest((IRequest)requestContext); + var req = new ServiceRequest((IRequest)requestContext); return GetSession(req); } @@ -60,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security public Task GetUser(object requestContext) { - var req = new ServiceStackServiceRequest((IRequest)requestContext); + var req = new ServiceRequest((IRequest)requestContext); return GetUser(req); } } -- cgit v1.2.3 From 46efa464d851d3f78b74ac02d061388115cf6d66 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 3 Nov 2016 21:18:51 -0400 Subject: move classes --- .../Emby.Server.Implementations.csproj | 5 + .../HttpServer/IHttpListener.cs | 46 ++++ .../HttpServer/Security/AuthService.cs | 246 +++++++++++++++++++++ .../HttpServer/Security/AuthorizationContext.cs | 195 ++++++++++++++++ .../HttpServer/Security/SessionContext.cs | 67 ++++++ .../HttpServer/StreamWriter.cs | 127 +++++++++++ .../HttpServer/HttpListenerHost.cs | 1 + .../HttpServer/HttpResultFactory.cs | 4 +- .../HttpServer/IHttpListener.cs | 46 ---- .../HttpServer/ResponseFilter.cs | 1 - .../HttpServer/Security/AuthService.cs | 246 --------------------- .../HttpServer/Security/AuthorizationContext.cs | 195 ---------------- .../HttpServer/Security/SessionContext.cs | 67 ------ .../SocketSharp/WebSocketSharpListener.cs | 1 + .../HttpServer/StreamWriter.cs | 127 ----------- .../MediaBrowser.Server.Implementations.csproj | 5 - .../ApplicationHost.cs | 2 +- MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 17 +- 18 files changed, 699 insertions(+), 699 deletions(-) create mode 100644 Emby.Server.Implementations/HttpServer/IHttpListener.cs create mode 100644 Emby.Server.Implementations/HttpServer/Security/AuthService.cs create mode 100644 Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs create mode 100644 Emby.Server.Implementations/HttpServer/Security/SessionContext.cs create mode 100644 Emby.Server.Implementations/HttpServer/StreamWriter.cs delete mode 100644 MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs delete mode 100644 MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs delete mode 100644 MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs delete mode 100644 MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs delete mode 100644 MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs (limited to 'MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs') diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 7eb6a67d4..3c416d958 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -67,6 +67,11 @@ + + + + + diff --git a/Emby.Server.Implementations/HttpServer/IHttpListener.cs b/Emby.Server.Implementations/HttpServer/IHttpListener.cs new file mode 100644 index 000000000..9f96a8e49 --- /dev/null +++ b/Emby.Server.Implementations/HttpServer/IHttpListener.cs @@ -0,0 +1,46 @@ +using MediaBrowser.Controller.Net; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using MediaBrowser.Model.Services; + +namespace Emby.Server.Implementations.HttpServer +{ + public interface IHttpListener : IDisposable + { + /// + /// Gets or sets the error handler. + /// + /// The error handler. + Action ErrorHandler { get; set; } + + /// + /// Gets or sets the request handler. + /// + /// The request handler. + Func RequestHandler { get; set; } + + /// + /// Gets or sets the web socket handler. + /// + /// The web socket handler. + Action WebSocketConnected { get; set; } + + /// + /// Gets or sets the web socket connecting. + /// + /// The web socket connecting. + Action WebSocketConnecting { get; set; } + + /// + /// Starts this instance. + /// + /// The URL prefixes. + void Start(IEnumerable urlPrefixes); + + /// + /// Stops this instance. + /// + void Stop(); + } +} diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs new file mode 100644 index 000000000..4d00c9b19 --- /dev/null +++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs @@ -0,0 +1,246 @@ +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Connect; +using MediaBrowser.Controller.Devices; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Security; +using MediaBrowser.Controller.Session; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Emby.Server.Implementations.HttpServer.Security +{ + public class AuthService : IAuthService + { + private readonly IServerConfigurationManager _config; + + public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, IConnectManager connectManager, ISessionManager sessionManager, IDeviceManager deviceManager) + { + AuthorizationContext = authorizationContext; + _config = config; + DeviceManager = deviceManager; + SessionManager = sessionManager; + ConnectManager = connectManager; + UserManager = userManager; + } + + public IUserManager UserManager { get; private set; } + public IAuthorizationContext AuthorizationContext { get; private set; } + public IConnectManager ConnectManager { get; private set; } + public ISessionManager SessionManager { get; private set; } + public IDeviceManager DeviceManager { get; private set; } + + /// + /// Redirect the client to a specific URL if authentication failed. + /// If this property is null, simply `401 Unauthorized` is returned. + /// + public string HtmlRedirect { get; set; } + + public void Authenticate(IServiceRequest request, + IAuthenticationAttributes authAttribtues) + { + ValidateUser(request, authAttribtues); + } + + private void ValidateUser(IServiceRequest request, + IAuthenticationAttributes authAttribtues) + { + // This code is executed before the service + var auth = AuthorizationContext.GetAuthorizationInfo(request); + + if (!IsExemptFromAuthenticationToken(auth, authAttribtues)) + { + var valid = IsValidConnectKey(auth.Token); + + if (!valid) + { + ValidateSecurityToken(request, auth.Token); + } + } + + var user = string.IsNullOrWhiteSpace(auth.UserId) + ? null + : UserManager.GetUserById(auth.UserId); + + if (user == null & !string.IsNullOrWhiteSpace(auth.UserId)) + { + throw new SecurityException("User with Id " + auth.UserId + " not found"); + } + + if (user != null) + { + ValidateUserAccess(user, request, authAttribtues, auth); + } + + var info = GetTokenInfo(request); + + if (!IsExemptFromRoles(auth, authAttribtues, info)) + { + var roles = authAttribtues.GetRoles().ToList(); + + ValidateRoles(roles, user); + } + + if (!string.IsNullOrWhiteSpace(auth.DeviceId) && + !string.IsNullOrWhiteSpace(auth.Client) && + !string.IsNullOrWhiteSpace(auth.Device)) + { + SessionManager.LogSessionActivity(auth.Client, + auth.Version, + auth.DeviceId, + auth.Device, + request.RemoteIp, + user); + } + } + + private void ValidateUserAccess(User user, IServiceRequest request, + IAuthenticationAttributes authAttribtues, + AuthorizationInfo auth) + { + if (user.Policy.IsDisabled) + { + throw new SecurityException("User account has been disabled.") + { + SecurityExceptionType = SecurityExceptionType.Unauthenticated + }; + } + + if (!user.Policy.IsAdministrator && + !authAttribtues.EscapeParentalControl && + !user.IsParentalScheduleAllowed()) + { + request.AddResponseHeader("X-Application-Error-Code", "ParentalControl"); + + throw new SecurityException("This user account is not allowed access at this time.") + { + SecurityExceptionType = SecurityExceptionType.ParentalControl + }; + } + + if (!string.IsNullOrWhiteSpace(auth.DeviceId)) + { + if (!DeviceManager.CanAccessDevice(user.Id.ToString("N"), auth.DeviceId)) + { + throw new SecurityException("User is not allowed access from this device.") + { + SecurityExceptionType = SecurityExceptionType.ParentalControl + }; + } + } + } + + private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues) + { + if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) + { + return true; + } + + return false; + } + + private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, AuthenticationInfo tokenInfo) + { + if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) + { + return true; + } + + if (string.IsNullOrWhiteSpace(auth.Token)) + { + return true; + } + + if (tokenInfo != null && string.IsNullOrWhiteSpace(tokenInfo.UserId)) + { + return true; + } + + return false; + } + + private void ValidateRoles(List roles, User user) + { + if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) + { + if (user == null || !user.Policy.IsAdministrator) + { + throw new SecurityException("User does not have admin access.") + { + SecurityExceptionType = SecurityExceptionType.Unauthenticated + }; + } + } + if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase)) + { + if (user == null || !user.Policy.EnableContentDeletion) + { + throw new SecurityException("User does not have delete access.") + { + SecurityExceptionType = SecurityExceptionType.Unauthenticated + }; + } + } + if (roles.Contains("download", StringComparer.OrdinalIgnoreCase)) + { + if (user == null || !user.Policy.EnableContentDownloading) + { + throw new SecurityException("User does not have download access.") + { + SecurityExceptionType = SecurityExceptionType.Unauthenticated + }; + } + } + } + + private AuthenticationInfo GetTokenInfo(IServiceRequest request) + { + object info; + request.Items.TryGetValue("OriginalAuthenticationInfo", out info); + return info as AuthenticationInfo; + } + + private bool IsValidConnectKey(string token) + { + if (string.IsNullOrEmpty(token)) + { + return false; + } + + return ConnectManager.IsAuthorizationTokenValid(token); + } + + private void ValidateSecurityToken(IServiceRequest request, string token) + { + if (string.IsNullOrWhiteSpace(token)) + { + throw new SecurityException("Access token is required."); + } + + var info = GetTokenInfo(request); + + if (info == null) + { + throw new SecurityException("Access token is invalid or expired."); + } + + if (!info.IsActive) + { + throw new SecurityException("Access token has expired."); + } + + //if (!string.IsNullOrWhiteSpace(info.UserId)) + //{ + // var user = _userManager.GetUserById(info.UserId); + + // if (user == null || user.Configuration.IsDisabled) + // { + // throw new SecurityException("User account has been disabled."); + // } + //} + } + } +} diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs new file mode 100644 index 000000000..ec3dfeb60 --- /dev/null +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -0,0 +1,195 @@ +using MediaBrowser.Controller.Connect; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Security; +using System; +using System.Collections.Generic; +using System.Linq; +using MediaBrowser.Model.Services; + +namespace Emby.Server.Implementations.HttpServer.Security +{ + public class AuthorizationContext : IAuthorizationContext + { + private readonly IAuthenticationRepository _authRepo; + private readonly IConnectManager _connectManager; + + public AuthorizationContext(IAuthenticationRepository authRepo, IConnectManager connectManager) + { + _authRepo = authRepo; + _connectManager = connectManager; + } + + public AuthorizationInfo GetAuthorizationInfo(object requestContext) + { + var req = new ServiceRequest((IRequest)requestContext); + return GetAuthorizationInfo(req); + } + + public AuthorizationInfo GetAuthorizationInfo(IServiceRequest requestContext) + { + object cached; + if (requestContext.Items.TryGetValue("AuthorizationInfo", out cached)) + { + return (AuthorizationInfo)cached; + } + + return GetAuthorization(requestContext); + } + + /// + /// Gets the authorization. + /// + /// The HTTP req. + /// Dictionary{System.StringSystem.String}. + private AuthorizationInfo GetAuthorization(IServiceRequest httpReq) + { + var auth = GetAuthorizationDictionary(httpReq); + + string deviceId = null; + string device = null; + string client = null; + string version = null; + + if (auth != null) + { + auth.TryGetValue("DeviceId", out deviceId); + auth.TryGetValue("Device", out device); + auth.TryGetValue("Client", out client); + auth.TryGetValue("Version", out version); + } + + var token = httpReq.Headers["X-Emby-Token"]; + + if (string.IsNullOrWhiteSpace(token)) + { + token = httpReq.Headers["X-MediaBrowser-Token"]; + } + if (string.IsNullOrWhiteSpace(token)) + { + token = httpReq.QueryString["api_key"]; + } + + var info = new AuthorizationInfo + { + Client = client, + Device = device, + DeviceId = deviceId, + Version = version, + Token = token + }; + + if (!string.IsNullOrWhiteSpace(token)) + { + var result = _authRepo.Get(new AuthenticationInfoQuery + { + AccessToken = token + }); + + var tokenInfo = result.Items.FirstOrDefault(); + + if (tokenInfo != null) + { + info.UserId = tokenInfo.UserId; + + // TODO: Remove these checks for IsNullOrWhiteSpace + if (string.IsNullOrWhiteSpace(info.Client)) + { + info.Client = tokenInfo.AppName; + } + if (string.IsNullOrWhiteSpace(info.Device)) + { + info.Device = tokenInfo.DeviceName; + } + if (string.IsNullOrWhiteSpace(info.DeviceId)) + { + info.DeviceId = tokenInfo.DeviceId; + } + if (string.IsNullOrWhiteSpace(info.Version)) + { + info.Version = tokenInfo.AppVersion; + } + } + else + { + var user = _connectManager.GetUserFromExchangeToken(token); + if (user != null) + { + info.UserId = user.Id.ToString("N"); + } + } + httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo; + } + + httpReq.Items["AuthorizationInfo"] = info; + + return info; + } + + /// + /// Gets the auth. + /// + /// The HTTP req. + /// Dictionary{System.StringSystem.String}. + private Dictionary GetAuthorizationDictionary(IServiceRequest httpReq) + { + var auth = httpReq.Headers["X-Emby-Authorization"]; + + if (string.IsNullOrWhiteSpace(auth)) + { + auth = httpReq.Headers["Authorization"]; + } + + return GetAuthorization(auth); + } + + /// + /// Gets the authorization. + /// + /// The authorization header. + /// Dictionary{System.StringSystem.String}. + private Dictionary GetAuthorization(string authorizationHeader) + { + if (authorizationHeader == null) return null; + + var parts = authorizationHeader.Split(new[] { ' ' }, 2); + + // There should be at least to parts + if (parts.Length != 2) return null; + + // It has to be a digest request + if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + // Remove uptil the first space + authorizationHeader = parts[1]; + parts = authorizationHeader.Split(','); + + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var item in parts) + { + var param = item.Trim().Split(new[] { '=' }, 2); + + if (param.Length == 2) + { + var value = NormalizeValue (param[1].Trim(new[] { '"' })); + result.Add(param[0], value); + } + } + + return result; + } + + private string NormalizeValue(string value) + { + if (string.IsNullOrWhiteSpace (value)) + { + return value; + } + + return System.Net.WebUtility.HtmlEncode(value); + } + } +} diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs new file mode 100644 index 000000000..33dd4e2d7 --- /dev/null +++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs @@ -0,0 +1,67 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Security; +using MediaBrowser.Controller.Session; +using System.Threading.Tasks; +using MediaBrowser.Model.Services; + +namespace Emby.Server.Implementations.HttpServer.Security +{ + public class SessionContext : ISessionContext + { + private readonly IUserManager _userManager; + private readonly ISessionManager _sessionManager; + private readonly IAuthorizationContext _authContext; + + public SessionContext(IUserManager userManager, IAuthorizationContext authContext, ISessionManager sessionManager) + { + _userManager = userManager; + _authContext = authContext; + _sessionManager = sessionManager; + } + + public Task GetSession(IServiceRequest requestContext) + { + var authorization = _authContext.GetAuthorizationInfo(requestContext); + + //if (!string.IsNullOrWhiteSpace(authorization.Token)) + //{ + // var auth = GetTokenInfo(requestContext); + // if (auth != null) + // { + // return _sessionManager.GetSessionByAuthenticationToken(auth, authorization.DeviceId, requestContext.RemoteIp, authorization.Version); + // } + //} + + var user = string.IsNullOrWhiteSpace(authorization.UserId) ? null : _userManager.GetUserById(authorization.UserId); + return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.RemoteIp, user); + } + + private AuthenticationInfo GetTokenInfo(IServiceRequest request) + { + object info; + request.Items.TryGetValue("OriginalAuthenticationInfo", out info); + return info as AuthenticationInfo; + } + + public Task GetSession(object requestContext) + { + var req = new ServiceRequest((IRequest)requestContext); + return GetSession(req); + } + + public async Task GetUser(IServiceRequest requestContext) + { + var session = await GetSession(requestContext).ConfigureAwait(false); + + return session == null || !session.UserId.HasValue ? null : _userManager.GetUserById(session.UserId.Value); + } + + public Task GetUser(object requestContext) + { + var req = new ServiceRequest((IRequest)requestContext); + return GetUser(req); + } + } +} diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs new file mode 100644 index 000000000..15488abaa --- /dev/null +++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs @@ -0,0 +1,127 @@ +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.IO; +using MediaBrowser.Model.Services; + +namespace Emby.Server.Implementations.HttpServer +{ + /// + /// Class StreamWriter + /// + public class StreamWriter : IAsyncStreamWriter, IHasHeaders + { + private ILogger Logger { get; set; } + + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// Gets or sets the source stream. + /// + /// The source stream. + private Stream SourceStream { get; set; } + + /// + /// The _options + /// + private readonly IDictionary _options = new Dictionary(); + /// + /// Gets the options. + /// + /// The options. + public IDictionary Headers + { + get { return _options; } + } + + public Action OnComplete { get; set; } + public Action OnError { get; set; } + private readonly byte[] _bytes; + + /// + /// Initializes a new instance of the class. + /// + /// The source. + /// Type of the content. + /// The logger. + public StreamWriter(Stream source, string contentType, ILogger logger) + { + if (string.IsNullOrEmpty(contentType)) + { + throw new ArgumentNullException("contentType"); + } + + SourceStream = source; + Logger = logger; + + Headers["Content-Type"] = contentType; + + if (source.CanSeek) + { + Headers["Content-Length"] = source.Length.ToString(UsCulture); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The source. + /// Type of the content. + /// The logger. + public StreamWriter(byte[] source, string contentType, ILogger logger) + : this(new MemoryStream(source), contentType, logger) + { + if (string.IsNullOrEmpty(contentType)) + { + throw new ArgumentNullException("contentType"); + } + + _bytes = source; + Logger = logger; + + Headers["Content-Type"] = contentType; + + Headers["Content-Length"] = source.Length.ToString(UsCulture); + } + + public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) + { + try + { + if (_bytes != null) + { + await responseStream.WriteAsync(_bytes, 0, _bytes.Length); + } + else + { + using (var src = SourceStream) + { + await src.CopyToAsync(responseStream).ConfigureAwait(false); + } + } + } + catch (Exception ex) + { + Logger.ErrorException("Error streaming data", ex); + + if (OnError != null) + { + OnError(); + } + + throw; + } + finally + { + if (OnComplete != null) + { + OnComplete(); + } + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 71704f8e2..f00c81766 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -17,6 +17,7 @@ using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Emby.Server.Implementations.HttpServer; using MediaBrowser.Common.Net; using MediaBrowser.Common.Security; using MediaBrowser.Controller; diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index de41481cc..95e1a35e6 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -9,14 +9,12 @@ using System.IO; using System.Net; using System.Text; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using ServiceStack; -using ServiceStack.Web; using IRequest = MediaBrowser.Model.Services.IRequest; using MimeTypes = MediaBrowser.Model.Net.MimeTypes; +using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter; namespace MediaBrowser.Server.Implementations.HttpServer { diff --git a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs deleted file mode 100644 index 7db935d43..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs +++ /dev/null @@ -1,46 +0,0 @@ -using MediaBrowser.Controller.Net; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - public interface IHttpListener : IDisposable - { - /// - /// Gets or sets the error handler. - /// - /// The error handler. - Action ErrorHandler { get; set; } - - /// - /// Gets or sets the request handler. - /// - /// The request handler. - Func RequestHandler { get; set; } - - /// - /// Gets or sets the web socket handler. - /// - /// The web socket handler. - Action WebSocketConnected { get; set; } - - /// - /// Gets or sets the web socket connecting. - /// - /// The web socket connecting. - Action WebSocketConnecting { get; set; } - - /// - /// Starts this instance. - /// - /// The URL prefixes. - void Start(IEnumerable urlPrefixes); - - /// - /// Stops this instance. - /// - void Stop(); - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs index f5a11ae1f..6247e4c17 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/ResponseFilter.cs @@ -1,6 +1,5 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Server.Implementations.HttpServer.SocketSharp; -using ServiceStack.Web; using System; using System.Globalization; using System.Net; diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs deleted file mode 100644 index d8f7d889c..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ /dev/null @@ -1,246 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Connect; -using MediaBrowser.Controller.Devices; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Security; -using MediaBrowser.Controller.Session; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace MediaBrowser.Server.Implementations.HttpServer.Security -{ - public class AuthService : IAuthService - { - private readonly IServerConfigurationManager _config; - - public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, IConnectManager connectManager, ISessionManager sessionManager, IDeviceManager deviceManager) - { - AuthorizationContext = authorizationContext; - _config = config; - DeviceManager = deviceManager; - SessionManager = sessionManager; - ConnectManager = connectManager; - UserManager = userManager; - } - - public IUserManager UserManager { get; private set; } - public IAuthorizationContext AuthorizationContext { get; private set; } - public IConnectManager ConnectManager { get; private set; } - public ISessionManager SessionManager { get; private set; } - public IDeviceManager DeviceManager { get; private set; } - - /// - /// Redirect the client to a specific URL if authentication failed. - /// If this property is null, simply `401 Unauthorized` is returned. - /// - public string HtmlRedirect { get; set; } - - public void Authenticate(IServiceRequest request, - IAuthenticationAttributes authAttribtues) - { - ValidateUser(request, authAttribtues); - } - - private void ValidateUser(IServiceRequest request, - IAuthenticationAttributes authAttribtues) - { - // This code is executed before the service - var auth = AuthorizationContext.GetAuthorizationInfo(request); - - if (!IsExemptFromAuthenticationToken(auth, authAttribtues)) - { - var valid = IsValidConnectKey(auth.Token); - - if (!valid) - { - ValidateSecurityToken(request, auth.Token); - } - } - - var user = string.IsNullOrWhiteSpace(auth.UserId) - ? null - : UserManager.GetUserById(auth.UserId); - - if (user == null & !string.IsNullOrWhiteSpace(auth.UserId)) - { - throw new SecurityException("User with Id " + auth.UserId + " not found"); - } - - if (user != null) - { - ValidateUserAccess(user, request, authAttribtues, auth); - } - - var info = GetTokenInfo(request); - - if (!IsExemptFromRoles(auth, authAttribtues, info)) - { - var roles = authAttribtues.GetRoles().ToList(); - - ValidateRoles(roles, user); - } - - if (!string.IsNullOrWhiteSpace(auth.DeviceId) && - !string.IsNullOrWhiteSpace(auth.Client) && - !string.IsNullOrWhiteSpace(auth.Device)) - { - SessionManager.LogSessionActivity(auth.Client, - auth.Version, - auth.DeviceId, - auth.Device, - request.RemoteIp, - user); - } - } - - private void ValidateUserAccess(User user, IServiceRequest request, - IAuthenticationAttributes authAttribtues, - AuthorizationInfo auth) - { - if (user.Policy.IsDisabled) - { - throw new SecurityException("User account has been disabled.") - { - SecurityExceptionType = SecurityExceptionType.Unauthenticated - }; - } - - if (!user.Policy.IsAdministrator && - !authAttribtues.EscapeParentalControl && - !user.IsParentalScheduleAllowed()) - { - request.AddResponseHeader("X-Application-Error-Code", "ParentalControl"); - - throw new SecurityException("This user account is not allowed access at this time.") - { - SecurityExceptionType = SecurityExceptionType.ParentalControl - }; - } - - if (!string.IsNullOrWhiteSpace(auth.DeviceId)) - { - if (!DeviceManager.CanAccessDevice(user.Id.ToString("N"), auth.DeviceId)) - { - throw new SecurityException("User is not allowed access from this device.") - { - SecurityExceptionType = SecurityExceptionType.ParentalControl - }; - } - } - } - - private bool IsExemptFromAuthenticationToken(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues) - { - if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) - { - return true; - } - - return false; - } - - private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues, AuthenticationInfo tokenInfo) - { - if (!_config.Configuration.IsStartupWizardCompleted && authAttribtues.AllowBeforeStartupWizard) - { - return true; - } - - if (string.IsNullOrWhiteSpace(auth.Token)) - { - return true; - } - - if (tokenInfo != null && string.IsNullOrWhiteSpace(tokenInfo.UserId)) - { - return true; - } - - return false; - } - - private void ValidateRoles(List roles, User user) - { - if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.Policy.IsAdministrator) - { - throw new SecurityException("User does not have admin access.") - { - SecurityExceptionType = SecurityExceptionType.Unauthenticated - }; - } - } - if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.Policy.EnableContentDeletion) - { - throw new SecurityException("User does not have delete access.") - { - SecurityExceptionType = SecurityExceptionType.Unauthenticated - }; - } - } - if (roles.Contains("download", StringComparer.OrdinalIgnoreCase)) - { - if (user == null || !user.Policy.EnableContentDownloading) - { - throw new SecurityException("User does not have download access.") - { - SecurityExceptionType = SecurityExceptionType.Unauthenticated - }; - } - } - } - - private AuthenticationInfo GetTokenInfo(IServiceRequest request) - { - object info; - request.Items.TryGetValue("OriginalAuthenticationInfo", out info); - return info as AuthenticationInfo; - } - - private bool IsValidConnectKey(string token) - { - if (string.IsNullOrEmpty(token)) - { - return false; - } - - return ConnectManager.IsAuthorizationTokenValid(token); - } - - private void ValidateSecurityToken(IServiceRequest request, string token) - { - if (string.IsNullOrWhiteSpace(token)) - { - throw new SecurityException("Access token is required."); - } - - var info = GetTokenInfo(request); - - if (info == null) - { - throw new SecurityException("Access token is invalid or expired."); - } - - if (!info.IsActive) - { - throw new SecurityException("Access token has expired."); - } - - //if (!string.IsNullOrWhiteSpace(info.UserId)) - //{ - // var user = _userManager.GetUserById(info.UserId); - - // if (user == null || user.Configuration.IsDisabled) - // { - // throw new SecurityException("User account has been disabled."); - // } - //} - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs deleted file mode 100644 index edbb5e512..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ /dev/null @@ -1,195 +0,0 @@ -using MediaBrowser.Controller.Connect; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Security; -using System; -using System.Collections.Generic; -using System.Linq; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Server.Implementations.HttpServer.Security -{ - public class AuthorizationContext : IAuthorizationContext - { - private readonly IAuthenticationRepository _authRepo; - private readonly IConnectManager _connectManager; - - public AuthorizationContext(IAuthenticationRepository authRepo, IConnectManager connectManager) - { - _authRepo = authRepo; - _connectManager = connectManager; - } - - public AuthorizationInfo GetAuthorizationInfo(object requestContext) - { - var req = new ServiceRequest((IRequest)requestContext); - return GetAuthorizationInfo(req); - } - - public AuthorizationInfo GetAuthorizationInfo(IServiceRequest requestContext) - { - object cached; - if (requestContext.Items.TryGetValue("AuthorizationInfo", out cached)) - { - return (AuthorizationInfo)cached; - } - - return GetAuthorization(requestContext); - } - - /// - /// Gets the authorization. - /// - /// The HTTP req. - /// Dictionary{System.StringSystem.String}. - private AuthorizationInfo GetAuthorization(IServiceRequest httpReq) - { - var auth = GetAuthorizationDictionary(httpReq); - - string deviceId = null; - string device = null; - string client = null; - string version = null; - - if (auth != null) - { - auth.TryGetValue("DeviceId", out deviceId); - auth.TryGetValue("Device", out device); - auth.TryGetValue("Client", out client); - auth.TryGetValue("Version", out version); - } - - var token = httpReq.Headers["X-Emby-Token"]; - - if (string.IsNullOrWhiteSpace(token)) - { - token = httpReq.Headers["X-MediaBrowser-Token"]; - } - if (string.IsNullOrWhiteSpace(token)) - { - token = httpReq.QueryString["api_key"]; - } - - var info = new AuthorizationInfo - { - Client = client, - Device = device, - DeviceId = deviceId, - Version = version, - Token = token - }; - - if (!string.IsNullOrWhiteSpace(token)) - { - var result = _authRepo.Get(new AuthenticationInfoQuery - { - AccessToken = token - }); - - var tokenInfo = result.Items.FirstOrDefault(); - - if (tokenInfo != null) - { - info.UserId = tokenInfo.UserId; - - // TODO: Remove these checks for IsNullOrWhiteSpace - if (string.IsNullOrWhiteSpace(info.Client)) - { - info.Client = tokenInfo.AppName; - } - if (string.IsNullOrWhiteSpace(info.Device)) - { - info.Device = tokenInfo.DeviceName; - } - if (string.IsNullOrWhiteSpace(info.DeviceId)) - { - info.DeviceId = tokenInfo.DeviceId; - } - if (string.IsNullOrWhiteSpace(info.Version)) - { - info.Version = tokenInfo.AppVersion; - } - } - else - { - var user = _connectManager.GetUserFromExchangeToken(token); - if (user != null) - { - info.UserId = user.Id.ToString("N"); - } - } - httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo; - } - - httpReq.Items["AuthorizationInfo"] = info; - - return info; - } - - /// - /// Gets the auth. - /// - /// The HTTP req. - /// Dictionary{System.StringSystem.String}. - private Dictionary GetAuthorizationDictionary(IServiceRequest httpReq) - { - var auth = httpReq.Headers["X-Emby-Authorization"]; - - if (string.IsNullOrWhiteSpace(auth)) - { - auth = httpReq.Headers["Authorization"]; - } - - return GetAuthorization(auth); - } - - /// - /// Gets the authorization. - /// - /// The authorization header. - /// Dictionary{System.StringSystem.String}. - private Dictionary GetAuthorization(string authorizationHeader) - { - if (authorizationHeader == null) return null; - - var parts = authorizationHeader.Split(new[] { ' ' }, 2); - - // There should be at least to parts - if (parts.Length != 2) return null; - - // It has to be a digest request - if (!string.Equals(parts[0], "MediaBrowser", StringComparison.OrdinalIgnoreCase)) - { - return null; - } - - // Remove uptil the first space - authorizationHeader = parts[1]; - parts = authorizationHeader.Split(','); - - var result = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (var item in parts) - { - var param = item.Trim().Split(new[] { '=' }, 2); - - if (param.Length == 2) - { - var value = NormalizeValue (param[1].Trim(new[] { '"' })); - result.Add(param[0], value); - } - } - - return result; - } - - private string NormalizeValue(string value) - { - if (string.IsNullOrWhiteSpace (value)) - { - return value; - } - - return System.Net.WebUtility.HtmlEncode(value); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs deleted file mode 100644 index f51ca55a8..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs +++ /dev/null @@ -1,67 +0,0 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Security; -using MediaBrowser.Controller.Session; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Server.Implementations.HttpServer.Security -{ - public class SessionContext : ISessionContext - { - private readonly IUserManager _userManager; - private readonly ISessionManager _sessionManager; - private readonly IAuthorizationContext _authContext; - - public SessionContext(IUserManager userManager, IAuthorizationContext authContext, ISessionManager sessionManager) - { - _userManager = userManager; - _authContext = authContext; - _sessionManager = sessionManager; - } - - public Task GetSession(IServiceRequest requestContext) - { - var authorization = _authContext.GetAuthorizationInfo(requestContext); - - //if (!string.IsNullOrWhiteSpace(authorization.Token)) - //{ - // var auth = GetTokenInfo(requestContext); - // if (auth != null) - // { - // return _sessionManager.GetSessionByAuthenticationToken(auth, authorization.DeviceId, requestContext.RemoteIp, authorization.Version); - // } - //} - - var user = string.IsNullOrWhiteSpace(authorization.UserId) ? null : _userManager.GetUserById(authorization.UserId); - return _sessionManager.LogSessionActivity(authorization.Client, authorization.Version, authorization.DeviceId, authorization.Device, requestContext.RemoteIp, user); - } - - private AuthenticationInfo GetTokenInfo(IServiceRequest request) - { - object info; - request.Items.TryGetValue("OriginalAuthenticationInfo", out info); - return info as AuthenticationInfo; - } - - public Task GetSession(object requestContext) - { - var req = new ServiceRequest((IRequest)requestContext); - return GetSession(req); - } - - public async Task GetUser(IServiceRequest requestContext) - { - var session = await GetSession(requestContext).ConfigureAwait(false); - - return session == null || !session.UserId.HasValue ? null : _userManager.GetUserById(session.UserId.Value); - } - - public Task GetUser(object requestContext) - { - var req = new ServiceRequest((IRequest)requestContext); - return GetUser(req); - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index 37bd00602..20d89d2eb 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Emby.Server.Implementations.HttpServer; using MediaBrowser.Common.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs deleted file mode 100644 index 7b88f12df..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ /dev/null @@ -1,127 +0,0 @@ -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// - /// Class StreamWriter - /// - public class StreamWriter : IAsyncStreamWriter, IHasHeaders - { - private ILogger Logger { get; set; } - - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// - /// Gets or sets the source stream. - /// - /// The source stream. - private Stream SourceStream { get; set; } - - /// - /// The _options - /// - private readonly IDictionary _options = new Dictionary(); - /// - /// Gets the options. - /// - /// The options. - public IDictionary Headers - { - get { return _options; } - } - - public Action OnComplete { get; set; } - public Action OnError { get; set; } - private readonly byte[] _bytes; - - /// - /// Initializes a new instance of the class. - /// - /// The source. - /// Type of the content. - /// The logger. - public StreamWriter(Stream source, string contentType, ILogger logger) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException("contentType"); - } - - SourceStream = source; - Logger = logger; - - Headers["Content-Type"] = contentType; - - if (source.CanSeek) - { - Headers["Content-Length"] = source.Length.ToString(UsCulture); - } - } - - /// - /// Initializes a new instance of the class. - /// - /// The source. - /// Type of the content. - /// The logger. - public StreamWriter(byte[] source, string contentType, ILogger logger) - : this(new MemoryStream(source), contentType, logger) - { - if (string.IsNullOrEmpty(contentType)) - { - throw new ArgumentNullException("contentType"); - } - - _bytes = source; - Logger = logger; - - Headers["Content-Type"] = contentType; - - Headers["Content-Length"] = source.Length.ToString(UsCulture); - } - - public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) - { - try - { - if (_bytes != null) - { - await responseStream.WriteAsync(_bytes, 0, _bytes.Length); - } - else - { - using (var src = SourceStream) - { - await src.CopyToAsync(responseStream).ConfigureAwait(false); - } - } - } - catch (Exception ex) - { - Logger.ErrorException("Error streaming data", ex); - - if (OnError != null) - { - OnError(); - } - - throw; - } - finally - { - if (OnComplete != null) - { - OnComplete(); - } - } - } - } -} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index b229a1d19..9af765c23 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -122,8 +122,6 @@ - - @@ -131,14 +129,11 @@ - - - diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 077a58938..e9d6b4999 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -55,7 +55,6 @@ using MediaBrowser.Server.Implementations.Connect; using MediaBrowser.Server.Implementations.Devices; using MediaBrowser.Server.Implementations.EntryPoints; using MediaBrowser.Server.Implementations.HttpServer; -using MediaBrowser.Server.Implementations.HttpServer.Security; using MediaBrowser.Server.Implementations.IO; using MediaBrowser.Server.Implementations.LiveTv; using MediaBrowser.Server.Implementations.Localization; @@ -106,6 +105,7 @@ using Emby.Server.Implementations.Collections; using Emby.Server.Implementations.Devices; using Emby.Server.Implementations.Dto; using Emby.Server.Implementations.FileOrganization; +using Emby.Server.Implementations.HttpServer.Security; using Emby.Server.Implementations.Library; using Emby.Server.Implementations.LiveTv; using Emby.Server.Implementations.MediaEncoder; diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index ba1e2641b..2ea3309b0 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -582,14 +582,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers if (!string.IsNullOrWhiteSpace(val)) { - var parts = val.Split('/') - .Select(i => i.Trim()) - .Where(i => !string.IsNullOrWhiteSpace(i)); - - foreach (var p in parts) - { - item.AddStudio(p); - } + //var parts = val.Split('/') + // .Select(i => i.Trim()) + // .Where(i => !string.IsNullOrWhiteSpace(i)); + + //foreach (var p in parts) + //{ + // item.AddStudio(p); + //} + item.AddStudio(val); } break; } -- cgit v1.2.3