diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs | 195 |
1 files changed, 135 insertions, 60 deletions
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs index 4b699c018..1d17c641d 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs @@ -1,12 +1,13 @@ 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 ServiceStack; -using ServiceStack.Auth; -using ServiceStack.Web; using System; -using System.Collections.Specialized; +using System.Collections.Generic; using System.Linq; namespace MediaBrowser.Server.Implementations.HttpServer.Security @@ -15,25 +16,21 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security { private readonly IServerConfigurationManager _config; - public AuthService(IUserManager userManager, ISessionManager sessionManager, IAuthorizationContext authorizationContext, 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 ISessionManager SessionManager { get; private set; } public IAuthorizationContext AuthorizationContext { get; private set; } - - /// <summary> - /// Restrict authentication to a specific <see cref="IAuthProvider"/>. - /// For example, if this attribute should only permit access - /// if the user is authenticated with <see cref="BasicAuthProvider"/>, - /// you should set this property to <see cref="BasicAuthProvider.Name"/>. - /// </summary> - public string Provider { get; set; } + public IConnectManager ConnectManager { get; private set; } + public ISessionManager SessionManager { get; private set; } + public IDeviceManager DeviceManager { get; private set; } /// <summary> /// Redirect the client to a specific URL if authentication failed. @@ -41,33 +38,25 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security /// </summary> public string HtmlRedirect { get; set; } - public void Authenticate(IRequest request, - IResponse response, - object requestDto, - bool allowLocal, - string[] roles) + public void Authenticate(IServiceRequest request, + IAuthenticationAttributes authAttribtues) { - if (HostContext.HasValidAuthSecret(request)) - return; - - //ExecuteBasic(req, res, requestDto); //first check if session is authenticated - //if (res.IsClosed) return; //AuthenticateAttribute already closed the request (ie auth failed) - - ValidateUser(request, allowLocal, roles); + ValidateUser(request, authAttribtues); } - private void ValidateUser(IRequest req, bool allowLocal, - string[] roles) + private void ValidateUser(IServiceRequest request, + IAuthenticationAttributes authAttribtues) { - //This code is executed before the service - var auth = AuthorizationContext.GetAuthorizationInfo(req); + // This code is executed before the service + var auth = AuthorizationContext.GetAuthorizationInfo(request); - if (!string.IsNullOrWhiteSpace(auth.Token) - || _config.Configuration.SecureApps2.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + if (!IsExemptFromAuthenticationToken(auth, authAttribtues)) { - if (!allowLocal || !req.IsLocal) + var valid = IsValidConnectKey(auth.Token); + + if (!valid) { - SessionManager.ValidateSecurityToken(auth.Token); + ValidateSecurityToken(request, auth.Token); } } @@ -77,20 +66,19 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security if (user == null & !string.IsNullOrWhiteSpace(auth.UserId)) { - throw new ArgumentException("User with Id " + auth.UserId + " not found"); + throw new SecurityException("User with Id " + auth.UserId + " not found"); } - if (user != null && user.Configuration.IsDisabled) + if (user != null) { - throw new AuthenticationException("User account has been disabled."); + ValidateUserAccess(user, request, authAttribtues, auth); } - if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) + if (!IsExemptFromRoles(auth, authAttribtues)) { - if (user == null || !user.Configuration.IsAdministrator) - { - throw new ArgumentException("Administrative access is required for this request."); - } + var roles = authAttribtues.GetRoles().ToList(); + + ValidateRoles(roles, user); } if (!string.IsNullOrWhiteSpace(auth.DeviceId) && @@ -101,45 +89,132 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security auth.Version, auth.DeviceId, auth.Device, - req.RemoteIp, + request.RemoteIp, user); } } - protected bool DoHtmlRedirectIfConfigured(IRequest req, IResponse res, bool includeRedirectParam = false) + private void ValidateUserAccess(User user, IServiceRequest request, + IAuthenticationAttributes authAttribtues, + AuthorizationInfo auth) { - var htmlRedirect = this.HtmlRedirect ?? AuthenticateService.HtmlRedirect; - if (htmlRedirect != null && req.ResponseContentType.MatchesContentType(MimeTypes.Html)) + 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) { - DoHtmlRedirect(htmlRedirect, req, res, includeRedirectParam); return true; } - return false; + + return _config.Configuration.InsecureApps7.Contains(auth.Client ?? string.Empty, + StringComparer.OrdinalIgnoreCase); } - public static void DoHtmlRedirect(string redirectUrl, IRequest req, IResponse res, bool includeRedirectParam) + private bool IsExemptFromRoles(AuthorizationInfo auth, IAuthenticationAttributes authAttribtues) { - var url = req.ResolveAbsoluteUrl(redirectUrl); - if (includeRedirectParam) + if (!_config.Configuration.IsStartupWizardCompleted && + authAttribtues.AllowBeforeStartupWizard) { - var absoluteRequestPath = req.ResolveAbsoluteUrl("~" + req.PathInfo + ToQueryString(req.QueryString)); - url = url.AddQueryParam(HostContext.ResolveLocalizedString(LocalizedStrings.Redirect), absoluteRequestPath); + return true; } - res.RedirectToUrl(url); + return false; + } + + private void ValidateRoles(List<string> 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 + }; + } + } } - private static string ToQueryString(INameValueCollection queryStringCollection) + private bool IsValidConnectKey(string token) { - return ToQueryString((NameValueCollection)queryStringCollection.Original); + if (string.IsNullOrEmpty(token)) + { + return false; + } + + return ConnectManager.IsAuthorizationTokenValid(token); } - private static string ToQueryString(NameValueCollection queryStringCollection) + private void ValidateSecurityToken(IServiceRequest request, string token) { - if (queryStringCollection == null || queryStringCollection.Count == 0) - return String.Empty; + if (string.IsNullOrWhiteSpace(token)) + { + throw new SecurityException("Access token is invalid or expired."); + } + + var info = (AuthenticationInfo)request.Items["OriginalAuthenticationInfo"]; + + 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); - return "?" + queryStringCollection.ToFormUrlEncoded(); + // if (user == null || user.Configuration.IsDisabled) + // { + // throw new SecurityException("User account has been disabled."); + // } + //} } } } |
