diff --git a/Oqtane.Client/Modules/Admin/Files/Edit.razor b/Oqtane.Client/Modules/Admin/Files/Edit.razor index 4f6054db..64694717 100644 --- a/Oqtane.Client/Modules/Admin/Files/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Files/Edit.razor @@ -61,10 +61,12 @@ @if (!_isSystem) { + @((MarkupString)" ") } @Localizer["Cancel"] @if (!_isSystem && PageState.QueryString.ContainsKey("id")) { + @((MarkupString)" ") }
diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index d687c657..dc6e04a3 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -30,14 +30,16 @@ namespace Oqtane.Controllers private readonly IFolderRepository _folders; private readonly IUserPermissions _userPermissions; private readonly ILogManager _logger; + private readonly Alias _alias; - public FileController(IWebHostEnvironment environment, IFileRepository files, IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger) + public FileController(IWebHostEnvironment environment, IFileRepository files, IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager) { _environment = environment; _files = files; _folders = folders; _userPermissions = userPermissions; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/?folder=x @@ -48,11 +50,17 @@ namespace Oqtane.Controllers int folderid; if (int.TryParse(folder, out folderid)) { - Folder f = _folders.GetFolder(folderid); - if (f != null && _userPermissions.IsAuthorized(User, PermissionNames.Browse, f.Permissions)) + Folder Folder = _folders.GetFolder(folderid); + if (Folder != null && Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Browse, Folder.Permissions)) { files = _files.GetFiles(folderid).ToList(); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Get Attempt {FolderId}", folder); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + files = null; + } } else { @@ -67,6 +75,12 @@ namespace Oqtane.Controllers } } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Get Attempt {Folder}", folder); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + files = null; + } } return files; @@ -76,27 +90,18 @@ namespace Oqtane.Controllers [HttpGet("{siteId}/{path}")] public IEnumerable Get(int siteId, string path) { - var folderPath = WebUtility.UrlDecode(path); - Folder folder = _folders.GetFolder(siteId, folderPath); List files; - if (folder != null) + + Folder folder = _folders.GetFolder(siteId, WebUtility.UrlDecode(path)); + if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) { - if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) - { - files = _files.GetFiles(folder.FolderId).ToList(); - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Folder {folder}", folder); - HttpContext.Response.StatusCode = 401; - return null; - } + files = _files.GetFiles(folder.FolderId).ToList(); } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "Folder Not Found {SiteId} {Path}", siteId, path); - HttpContext.Response.StatusCode = 404; - return null; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Get Attempt {SiteId} {Path}", siteId, path); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + files = null; } return files; @@ -107,23 +112,14 @@ namespace Oqtane.Controllers public Models.File Get(int id) { Models.File file = _files.GetFile(id); - if (file != null) + if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions)) { - if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions)) - { - return file; - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access File {File}", file); - HttpContext.Response.StatusCode = 401; - return null; - } + return file; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Not Found {FileId}", id); - HttpContext.Response.StatusCode = 404; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Get Attempt {FileId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -133,19 +129,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Models.File Put(int id, [FromBody] Models.File file) { - if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.FolderId, PermissionNames.Edit)) + var File = _files.GetFile(file.FileId, false); + if (ModelState.IsValid && File != null && File.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.FolderId, PermissionNames.Edit)) { - file.Folder = _folders.GetFolder(file.FolderId); - Models.File _file = _files.GetFile(id, false); - if (_file.Name != file.Name || _file.FolderId != file.FolderId) + if (File.Name != file.Name || File.FolderId != file.FolderId) { string folderpath = _folders.GetFolderPath(file.Folder); if (!Directory.Exists(folderpath)) { Directory.CreateDirectory(folderpath); } - - System.IO.File.Move(_files.GetFilePath(_file), Path.Combine(folderpath, file.Name)); + System.IO.File.Move(_files.GetFilePath(File), Path.Combine(folderpath, file.Name)); } file.Extension = Path.GetExtension(file.Name).ToLower().Replace(".", ""); @@ -154,8 +148,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update File {File}", file); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Put Attempt {File}", file); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; file = null; } @@ -168,30 +162,22 @@ namespace Oqtane.Controllers public void Delete(int id) { Models.File file = _files.GetFile(id); - if (file != null) + if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.Folder.FolderId, PermissionNames.Edit)) { - if (_userPermissions.IsAuthorized(User, EntityNames.Folder, file.Folder.FolderId, PermissionNames.Edit)) - { - _files.DeleteFile(id); + _files.DeleteFile(id); - string filepath = _files.GetFilePath(file); - if (System.IO.File.Exists(filepath)) - { - System.IO.File.Delete(filepath); - } - - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "File Deleted {File}", file); - } - else + string filepath = _files.GetFilePath(file); + if (System.IO.File.Exists(filepath)) { - _logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete File {FileId}", id); - HttpContext.Response.StatusCode = 401; + System.IO.File.Delete(filepath); } + + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "File Deleted {File}", file); } else { - _logger.Log(LogLevel.Error, this, LogFunction.Delete, "File Not Found {FileId}", id); - HttpContext.Response.StatusCode = 404; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Delete Attempt {FileId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } @@ -200,55 +186,57 @@ namespace Oqtane.Controllers public Models.File UploadFile(string url, string folderid) { Models.File file = null; - Folder folder = _folders.GetFolder(int.Parse(folderid)); - if (folder == null || !_userPermissions.IsAuthorized(User, PermissionNames.Edit, folder.Permissions)) + Folder folder = null; + int FolderId; + if (int.TryParse(folderid, out FolderId)) { - _logger.Log(LogLevel.Error, this, LogFunction.Create, - "User Not Authorized To Download File {Url} {FolderId}", url, folderid); - HttpContext.Response.StatusCode = 401; - return file; + folder = _folders.GetFolder(FolderId); } - string folderPath = _folders.GetFolderPath(folder); - CreateDirectory(folderPath); - - string filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1); - // check for allowable file extensions - if (!Constants.UploadableFiles.Split(',') - .Contains(Path.GetExtension(filename).ToLower().Replace(".", ""))) + if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Edit, folder.Permissions)) { - _logger.Log(LogLevel.Error, this, LogFunction.Create, - "File Could Not Be Downloaded From Url Due To Its File Extension {Url}", url); - HttpContext.Response.StatusCode = (int) HttpStatusCode.Conflict; - return file; - } + string folderPath = _folders.GetFolderPath(folder); + CreateDirectory(folderPath); - if (!filename.IsPathOrFileValid()) - { - _logger.Log(LogLevel.Error, this, LogFunction.Create, - $"File Could Not Be Downloaded From Url Due To Its File Name Not Allowed {url}"); - HttpContext.Response.StatusCode = (int) HttpStatusCode.Conflict; - return file; - } - - try - { - var client = new WebClient(); - string targetPath = Path.Combine(folderPath, filename); - // remove file if it already exists - if (System.IO.File.Exists(targetPath)) + string filename = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1); + // check for allowable file extensions + if (!Constants.UploadableFiles.Split(',').Contains(Path.GetExtension(filename).ToLower().Replace(".", ""))) { - System.IO.File.Delete(targetPath); + _logger.Log(LogLevel.Error, this, LogFunction.Create, "File Could Not Be Downloaded From Url Due To Its File Extension {Url}", url); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; + return file; } - client.DownloadFile(url, targetPath); - file = _files.AddFile(CreateFile(filename, folder.FolderId, targetPath)); + if (!filename.IsPathOrFileValid()) + { + _logger.Log(LogLevel.Error, this, LogFunction.Create, $"File Could Not Be Downloaded From Url Due To Its File Name Not Allowed {url}"); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict; + return file; + } + + try + { + var client = new WebClient(); + string targetPath = Path.Combine(folderPath, filename); + // remove file if it already exists + if (System.IO.File.Exists(targetPath)) + { + System.IO.File.Delete(targetPath); + } + + client.DownloadFile(url, targetPath); + file = _files.AddFile(CreateFile(filename, folder.FolderId, targetPath)); + } + catch + { + _logger.Log(LogLevel.Error, this, LogFunction.Create, "File Could Not Be Downloaded From Url {Url}", url); + } } - catch + else { - _logger.Log(LogLevel.Error, this, LogFunction.Create, - "File Could Not Be Downloaded From Url {Url}", url); + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Upload Attempt {FolderId} {Url}", folderid, url); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } return file; @@ -271,25 +259,25 @@ namespace Oqtane.Controllers string folderPath = ""; - if (int.TryParse(folder, out int folderId)) + int FolderId; + if (int.TryParse(folder, out FolderId)) { - Folder virtualFolder = _folders.GetFolder(folderId); - if (virtualFolder != null && - _userPermissions.IsAuthorized(User, PermissionNames.Edit, virtualFolder.Permissions)) + Folder Folder = _folders.GetFolder(FolderId); + if (Folder != null && Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Edit, Folder.Permissions)) { - folderPath = _folders.GetFolderPath(virtualFolder); + folderPath = _folders.GetFolderPath(Folder); } } else { + FolderId = -1; if (User.IsInRole(RoleNames.Host)) { folderPath = GetFolderPath(folder); - folderId = -1; } } - if (!String.IsNullOrEmpty(folderPath)) + if (!string.IsNullOrEmpty(folderPath)) { CreateDirectory(folderPath); using (var stream = new FileStream(Path.Combine(folderPath, file.FileName), FileMode.Create)) @@ -298,16 +286,15 @@ namespace Oqtane.Controllers } string upload = await MergeFile(folderPath, file.FileName); - if (upload != "" && folderId != -1) + if (upload != "" && FolderId != -1) { - _files.AddFile(CreateFile(upload, folderId, Path.Combine(folderPath, upload))); + _files.AddFile(CreateFile(upload, FolderId, Path.Combine(folderPath, upload))); } } else { - _logger.Log(LogLevel.Error, this, LogFunction.Create, - "User Not Authorized To Upload File {Folder} {File}", folder, file); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Upload Attempt {Folder} {File}", folder, file); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } @@ -466,32 +453,26 @@ namespace Oqtane.Controllers private IActionResult Download(int id, bool asAttachment) { var file = _files.GetFile(id); - if (file != null) + if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions)) { - if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions)) + var filepath = _files.GetFilePath(file); + if (System.IO.File.Exists(filepath)) { - var filepath = _files.GetFilePath(file); - if (System.IO.File.Exists(filepath)) - { - var result = asAttachment - ? PhysicalFile(filepath, file.GetMimeType(), file.Name) - : PhysicalFile(filepath, file.GetMimeType()); - return result; - } - - _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FileId} {FilePath}", id, filepath); - HttpContext.Response.StatusCode = 404; + var result = asAttachment + ? PhysicalFile(filepath, file.GetMimeType(), file.Name) + : PhysicalFile(filepath, file.GetMimeType()); + return result; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access File {FileId}", id); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FileId} {FilePath}", id, filepath); + HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; } } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Not Found {FileId}", id); - HttpContext.Response.StatusCode = 404; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Access Attempt {FileId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } string errorPath = Path.Combine(GetFolderPath("images"), "error.png"); diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index 9093631f..8ae32116 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -21,16 +21,16 @@ namespace Oqtane.Controllers private readonly IWebHostEnvironment _environment; private readonly IFolderRepository _folders; private readonly IUserPermissions _userPermissions; - private readonly ITenantManager _tenantManager; private readonly ILogManager _logger; + private readonly Alias _alias; - public FolderController(IWebHostEnvironment environment, IFolderRepository folders, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger) + public FolderController(IWebHostEnvironment environment, IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager) { _environment = environment; _folders = folders; _userPermissions = userPermissions; - _tenantManager = tenantManager; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/?siteid=x @@ -38,13 +38,23 @@ namespace Oqtane.Controllers public IEnumerable Get(string siteid) { List folders = new List(); - foreach (Folder folder in _folders.GetFolders(int.Parse(siteid))) + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { - if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) + foreach (Folder folder in _folders.GetFolders(SiteId)) { - folders.Add(folder); + if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) + { + folders.Add(folder); + } } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + folders = null; + } return folders; } @@ -53,14 +63,14 @@ namespace Oqtane.Controllers public Folder Get(int id) { Folder folder = _folders.GetFolder(id); - if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) + if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) { return folder; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Folder {Folder}", folder); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Get Attempt {FolderId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -74,23 +84,14 @@ namespace Oqtane.Controllers folderPath = Utilities.PathCombine(folderPath, System.IO.Path.DirectorySeparatorChar.ToString()); } Folder folder = _folders.GetFolder(siteId, folderPath); - if (folder != null) - if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) - { - return folder; - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Folder {Folder}", - folder); - HttpContext.Response.StatusCode = 401; - return null; - } + if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions)) + { + return folder; + } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "Folder not found {path}", - path); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Get Attempt {Path} For Site {SiteId}", path, siteId); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -100,7 +101,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Folder Post([FromBody] Folder folder) { - if (ModelState.IsValid) + if (ModelState.IsValid && folder.SiteId == _alias.SiteId) { string permissions; if (folder.ParentId != null) @@ -129,17 +130,23 @@ namespace Oqtane.Controllers else { _logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Name Not Valid {Folder}", folder); - HttpContext.Response.StatusCode = 401; + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; folder = null; } } else { - _logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Folder {Folder}", folder); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Post Attempt {Folder}", folder); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; folder = null; } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Post Attempt {Folder}", folder); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + folder = null; + } return folder; } @@ -148,7 +155,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Folder Put(int id, [FromBody] Folder folder) { - if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Folder, folder.FolderId, PermissionNames.Edit)) + if (ModelState.IsValid && folder.SiteId == _alias.SiteId && _folders.GetFolder(folder.FolderId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Folder, folder.FolderId, PermissionNames.Edit)) { if (folder.IsPathValid()) { @@ -171,14 +178,14 @@ namespace Oqtane.Controllers else { _logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Name Not Valid {Folder}", folder); - HttpContext.Response.StatusCode = 401; + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; folder = null; } } else { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Folder {Folder}", folder); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Put Attempt {Folder}", folder); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; folder = null; } return folder; @@ -189,7 +196,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public void Put(int siteid, int folderid, int? parentid) { - if (_userPermissions.IsAuthorized(User, EntityNames.Folder, folderid, PermissionNames.Edit)) + if (siteid == _alias.SiteId && _folders.GetFolder(folderid, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Folder, folderid, PermissionNames.Edit)) { int order = 1; List folders = _folders.GetFolders(siteid).ToList(); @@ -206,8 +213,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Folder Order {SiteId} {FolderId} {ParentId}", siteid, folderid, parentid); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Update, "Unauthorized Folder Put Attempt {SiteId} {FolderId} {ParentId}", siteid, folderid, parentid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } @@ -216,26 +223,26 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public void Delete(int id) { - if (_userPermissions.IsAuthorized(User, EntityNames.Folder, id, PermissionNames.Edit)) + var folder = _folders.GetFolder(id, false); + if (folder != null && folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Folder, id, PermissionNames.Edit)) { - Models.Folder _folder = _folders.GetFolder(id, false); - if (Directory.Exists(GetFolderPath(_folder))) + if (Directory.Exists(GetFolderPath(folder))) { - Directory.Delete(GetFolderPath(_folder)); + Directory.Delete(GetFolderPath(folder)); } _folders.DeleteFolder(id); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Folder Deleted {FolderId}", id); } else { - _logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete Folder {FolderId}", id); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Folder Delete Attempt {FolderId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } private string GetFolderPath(Folder folder) { - return Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _tenantManager.GetTenant().TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path); + return Utilities.PathCombine(_environment.ContentRootPath, "Content", "Tenants", _alias.TenantId.ToString(), "Sites", folder.SiteId.ToString(), folder.Path); } } } diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index dc23374f..143150df 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -12,6 +12,7 @@ using Oqtane.Modules; using Oqtane.Shared; using Oqtane.Themes; using Microsoft.Extensions.Caching.Memory; +using System.Net; namespace Oqtane.Controllers { @@ -85,7 +86,7 @@ namespace Oqtane.Controllers } else { - HttpContext.Response.StatusCode = 401; + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } diff --git a/Oqtane.Server/Controllers/LanguageController.cs b/Oqtane.Server/Controllers/LanguageController.cs index b55f4bff..cbe67896 100644 --- a/Oqtane.Server/Controllers/LanguageController.cs +++ b/Oqtane.Server/Controllers/LanguageController.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Net; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Oqtane.Enums; @@ -14,28 +15,62 @@ namespace Oqtane.Controllers { private readonly ILanguageRepository _languages; private readonly ILogManager _logger; + private readonly Alias _alias; - public LanguageController(ILanguageRepository language, ILogManager logger) + public LanguageController(ILanguageRepository language, ILogManager logger, ITenantManager tenantManager) { _languages = language; _logger = logger; + _alias = tenantManager.GetAlias(); } [HttpGet] - public IEnumerable Get(string siteid) => _languages.GetLanguages(int.Parse(siteid)); + public IEnumerable Get(string siteid) + { + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) + { + return _languages.GetLanguages(SiteId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Language Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } [HttpGet("{id}")] - public Language Get(int id) => _languages.GetLanguage(id); + public Language Get(int id) + { + var language = _languages.GetLanguage(id); + if (language != null && language.SiteId == _alias.SiteId) + { + return language; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Language Get Attempt {LanguageId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } [HttpPost] [Authorize(Roles = RoleNames.Admin)] public Language Post([FromBody] Language language) { - if (ModelState.IsValid) + if (ModelState.IsValid && language.SiteId == _alias.SiteId) { language = _languages.AddLanguage(language); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Language Added {Language}", language); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Language Post Attempt {Language}", language); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + language = null; + } return language; } @@ -43,8 +78,18 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public void Delete(int id) { - _languages.DeleteLanguage(id); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Language Deleted {LanguageId}", id); + var language = _languages.GetLanguage(id); + if (language != null && language.SiteId == _alias.SiteId) + { + _languages.DeleteLanguage(id); + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Language Deleted {LanguageId}", id); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Language Delete Attempt {LanguageId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } + } } } diff --git a/Oqtane.Server/Controllers/LogController.cs b/Oqtane.Server/Controllers/LogController.cs index 244a2a60..34fc5b7c 100644 --- a/Oqtane.Server/Controllers/LogController.cs +++ b/Oqtane.Server/Controllers/LogController.cs @@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Authorization; using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Shared; +using Oqtane.Enums; +using System.Net; namespace Oqtane.Controllers { @@ -14,11 +16,13 @@ namespace Oqtane.Controllers { private readonly ILogManager _logger; private readonly ILogRepository _logs; + private readonly Alias _alias; - public LogController(ILogManager logger, ILogRepository logs) + public LogController(ILogManager logger, ILogRepository logs, ITenantManager tenantManager) { _logger = logger; _logs = logs; + _alias = tenantManager.GetAlias(); } // GET: api/?siteid=x&level=y&function=z&rows=50 @@ -26,7 +30,18 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public IEnumerable Get(string siteid, string level, string function, string rows) { - return _logs.GetLogs(int.Parse(siteid), level, function, int.Parse(rows)); + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) + { + return _logs.GetLogs(SiteId, level, function, int.Parse(rows)); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } // GET api//5 @@ -34,17 +49,32 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public Log Get(int id) { - return _logs.GetLog(id); + var log = _logs.GetLog(id); + if (log != null && log.SiteId == _alias.SiteId) + { + return log; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Get Attempt {LogId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } } // POST api/ [HttpPost] public void Post([FromBody] Log log) { - if (ModelState.IsValid) + if (ModelState.IsValid && log.SiteId == _alias.SiteId) { _logger.Log(log); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Post Attempt {Log}", log); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } } } diff --git a/Oqtane.Server/Controllers/ModuleController.cs b/Oqtane.Server/Controllers/ModuleController.cs index 0faba825..94c58b40 100644 --- a/Oqtane.Server/Controllers/ModuleController.cs +++ b/Oqtane.Server/Controllers/ModuleController.cs @@ -8,6 +8,7 @@ using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Security; +using System.Net; namespace Oqtane.Controllers { @@ -41,40 +42,52 @@ namespace Oqtane.Controllers [HttpGet] public IEnumerable Get(string siteid) { - List moduledefinitions = _moduleDefinitions.GetModuleDefinitions(int.Parse(siteid)).ToList(); - List settings = _settings.GetSettings(EntityNames.Module).ToList(); - List modules = new List(); - foreach (PageModule pagemodule in _pageModules.GetPageModules(int.Parse(siteid))) + + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { - if (_userPermissions.IsAuthorized(User,PermissionNames.View, pagemodule.Module.Permissions)) + List moduledefinitions = _moduleDefinitions.GetModuleDefinitions(SiteId).ToList(); + List settings = _settings.GetSettings(EntityNames.Module).ToList(); + + foreach (PageModule pagemodule in _pageModules.GetPageModules(SiteId)) { - Module module = new Module(); - module.SiteId = pagemodule.Module.SiteId; - module.ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName; - module.AllPages = pagemodule.Module.AllPages; - module.Permissions = pagemodule.Module.Permissions; - module.CreatedBy = pagemodule.Module.CreatedBy; - module.CreatedOn = pagemodule.Module.CreatedOn; - module.ModifiedBy = pagemodule.Module.ModifiedBy; - module.ModifiedOn = pagemodule.Module.ModifiedOn; - module.IsDeleted = pagemodule.IsDeleted; + if (_userPermissions.IsAuthorized(User, PermissionNames.View, pagemodule.Module.Permissions)) + { + Module module = new Module(); + module.SiteId = pagemodule.Module.SiteId; + module.ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName; + module.AllPages = pagemodule.Module.AllPages; + module.Permissions = pagemodule.Module.Permissions; + module.CreatedBy = pagemodule.Module.CreatedBy; + module.CreatedOn = pagemodule.Module.CreatedOn; + module.ModifiedBy = pagemodule.Module.ModifiedBy; + module.ModifiedOn = pagemodule.Module.ModifiedOn; + module.IsDeleted = pagemodule.IsDeleted; - module.PageModuleId = pagemodule.PageModuleId; - module.ModuleId = pagemodule.ModuleId; - module.PageId = pagemodule.PageId; - module.Title = pagemodule.Title; - module.Pane = pagemodule.Pane; - module.Order = pagemodule.Order; - module.ContainerType = pagemodule.ContainerType; + module.PageModuleId = pagemodule.PageModuleId; + module.ModuleId = pagemodule.ModuleId; + module.PageId = pagemodule.PageId; + module.Title = pagemodule.Title; + module.Pane = pagemodule.Pane; + module.Order = pagemodule.Order; + module.ContainerType = pagemodule.ContainerType; - module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName); - module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId) - .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); + module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName); + module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); - modules.Add(module); + modules.Add(module); + } } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + modules = null; + } + return modules; } @@ -83,19 +96,18 @@ namespace Oqtane.Controllers public Module Get(int id) { Module module = _modules.GetModule(id); - if (_userPermissions.IsAuthorized(User,PermissionNames.View, module.Permissions)) + if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, module.Permissions)) { List moduledefinitions = _moduleDefinitions.GetModuleDefinitions(module.SiteId).ToList(); module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName); module.Settings = _settings.GetSettings(EntityNames.Module, id) .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); - return module; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Module {Module}", module); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Get Attempt {ModuleId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -105,7 +117,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Module Post([FromBody] Module module) { - if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, module.PageId, PermissionNames.Edit)) + if (ModelState.IsValid && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, module.PageId, PermissionNames.Edit)) { module = _modules.AddModule(module); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); @@ -113,8 +125,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Module {Module}", module); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Post Attempt {Module}", module); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; module = null; } return module; @@ -125,7 +137,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Module Put(int id, [FromBody] Module module) { - if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit)) + if (ModelState.IsValid && module.SiteId == _alias.SiteId && _modules.GetModule(module.ModuleId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit)) { module = _modules.UpdateModule(module); if (module.AllPages) @@ -146,8 +158,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Module {Module}", module); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Put Attempt {Module}", module); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; module = null; } return module; @@ -158,7 +170,8 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public void Delete(int id) { - if (_userPermissions.IsAuthorized(User, EntityNames.Module, id, PermissionNames.Edit)) + var module = _modules.GetModule(id); + if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, module.ModuleId, PermissionNames.Edit)) { _modules.DeleteModule(id); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); @@ -166,8 +179,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete Module {ModuleId}", id); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Delete Attempt {ModuleId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } @@ -177,14 +190,15 @@ namespace Oqtane.Controllers public string Export(int moduleid) { string content = ""; - if (_userPermissions.IsAuthorized(User, EntityNames.Module, moduleid, PermissionNames.Edit)) + var module = _modules.GetModule(moduleid); + if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit)) { content = _modules.ExportModule(moduleid); } else { - _logger.Log(LogLevel.Error, this, LogFunction.Other, "User Not Authorized To Export Module {ModuleId}", moduleid); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Export Attempt {ModuleId}", moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } return content; } @@ -195,14 +209,15 @@ namespace Oqtane.Controllers public bool Import(int moduleid, [FromBody] string content) { bool success = false; - if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, moduleid, PermissionNames.Edit)) + var module = _modules.GetModule(moduleid); + if (ModelState.IsValid && module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit)) { success = _modules.ImportModule(moduleid, content); } else { - _logger.Log(LogLevel.Error, this, LogFunction.Other, "User Not Authorized To Import Module {ModuleId}", moduleid); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Module Import Attempt {ModuleId}", moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } return success; } diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index cd6d1cd7..6e945f6b 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -14,6 +14,7 @@ using Oqtane.Security; using System; using Microsoft.Extensions.DependencyInjection; using System.Text.Json; +using System.Net; namespace Oqtane.Controllers { @@ -29,6 +30,7 @@ namespace Oqtane.Controllers private readonly IServiceProvider _serviceProvider; private readonly ITenantManager _tenantManager; private readonly ILogManager _logger; + private readonly Alias _alias; public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ITenantManager tenantManager, ILogManager logger) { @@ -41,58 +43,113 @@ namespace Oqtane.Controllers _serviceProvider = serviceProvider; _tenantManager = tenantManager; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/?siteid=x [HttpGet] public IEnumerable Get(string siteid) { - List moduledefinitions = new List(); - foreach(ModuleDefinition moduledefinition in _moduleDefinitions.GetModuleDefinitions(int.Parse(siteid))) + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { - if (_userPermissions.IsAuthorized(User,PermissionNames.Utilize, moduledefinition.Permissions)) + List moduledefinitions = new List(); + foreach (ModuleDefinition moduledefinition in _moduleDefinitions.GetModuleDefinitions(SiteId)) { - moduledefinitions.Add(moduledefinition); + if (_userPermissions.IsAuthorized(User, PermissionNames.Utilize, moduledefinition.Permissions)) + { + moduledefinitions.Add(moduledefinition); + } } + return moduledefinitions; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; } - return moduledefinitions; } // GET api//5?siteid=x [HttpGet("{id}")] public ModuleDefinition Get(int id, string siteid) { - ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, int.Parse(siteid)); - if (_userPermissions.IsAuthorized(User,PermissionNames.Utilize, moduledefinition.Permissions)) + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { - return moduledefinition; + ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, SiteId); + if (_userPermissions.IsAuthorized(User, PermissionNames.Utilize, moduledefinition.Permissions)) + { + return moduledefinition; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Get Attempt {ModuleDefinitionId} {SiteId}", id, siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access ModuleDefinition {ModuleDefinition}", moduledefinition); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Get Attempt {ModuleDefinitionId} {SiteId}", id, siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } + // POST api/ + [HttpPost] + [Authorize(Roles = RoleNames.Host)] + public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition) + { + if (ModelState.IsValid && moduleDefinition.SiteId == _alias.SiteId) + { + string rootPath; + DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath); + string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template, Path.DirectorySeparatorChar.ToString()); + + if (moduleDefinition.Template.ToLower().Contains("internal")) + { + rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString()); + moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", Oqtane.Client"; + moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server"; + } + else + { + rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, moduleDefinition.Owner + "." + moduleDefinition.Name, Path.DirectorySeparatorChar.ToString()); + moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane"; + moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane"; + } + + ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition); + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Definition Created {ModuleDefinition}", moduleDefinition); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Post Attempt {ModuleDefinition}", moduleDefinition); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + moduleDefinition = null; + } + + return moduleDefinition; + } + // PUT api//5 [HttpPut("{id}")] [Authorize(Roles = RoleNames.Admin)] public void Put(int id, [FromBody] ModuleDefinition moduleDefinition) { - if (ModelState.IsValid) + if (ModelState.IsValid && moduleDefinition.SiteId == _alias.SiteId && _moduleDefinitions.GetModuleDefinition(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId) != null) { _moduleDefinitions.UpdateModuleDefinition(moduleDefinition); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Module Definition Updated {ModuleDefinition}", moduleDefinition); } - } - - [HttpGet("install")] - [Authorize(Roles = RoleNames.Host)] - public void InstallModules() - { - _logger.Log(LogLevel.Information, this, LogFunction.Create, "Modules Installed"); - _installationManager.InstallPackages(); + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Put Attempt {ModuleDefinition}", moduleDefinition); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } // DELETE api//5?siteid=x @@ -101,7 +158,7 @@ namespace Oqtane.Controllers public void Delete(int id, int siteid) { ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, siteid); - if (moduledefinition != null && Utilities.GetAssemblyName(moduledefinition.ServerManagerType) != "Oqtane.Server") + if (moduledefinition != null && moduledefinition.SiteId == _alias.SiteId && Utilities.GetAssemblyName(moduledefinition.ServerManagerType) != "Oqtane.Server") { // execute uninstall logic or scripts if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType)) @@ -157,6 +214,19 @@ namespace Oqtane.Controllers _moduleDefinitions.DeleteModuleDefinition(id); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized ModuleDefinition Delete Attempt {ModuleDefinitionId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } + } + + [HttpGet("install")] + [Authorize(Roles = RoleNames.Host)] + public void InstallModules() + { + _logger.Log(LogLevel.Information, this, LogFunction.Create, "Modules Installed"); + _installationManager.InstallPackages(); } // GET: api//templates @@ -189,37 +259,6 @@ namespace Oqtane.Controllers return templates; } - // POST api/ - [HttpPost] - [Authorize(Roles = RoleNames.Host)] - public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition) - { - if (ModelState.IsValid) - { - string rootPath; - DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath); - string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template,Path.DirectorySeparatorChar.ToString()); - - if (moduleDefinition.Template.ToLower().Contains("internal")) - { - rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString()); - moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", Oqtane.Client"; - moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server"; - } - else - { - rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, moduleDefinition.Owner + "." + moduleDefinition.Name, Path.DirectorySeparatorChar.ToString()); - moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane"; - moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane"; - } - - ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition); - _logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Definition Created {ModuleDefinition}", moduleDefinition); - } - - return moduleDefinition; - } - private void ProcessTemplatesRecursively(DirectoryInfo current, string rootPath, string rootFolder, string templatePath, ModuleDefinition moduleDefinition) { // process folder diff --git a/Oqtane.Server/Controllers/NotificationController.cs b/Oqtane.Server/Controllers/NotificationController.cs index fe721479..c4c22f87 100644 --- a/Oqtane.Server/Controllers/NotificationController.cs +++ b/Oqtane.Server/Controllers/NotificationController.cs @@ -7,6 +7,7 @@ using Oqtane.Shared; using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Security; +using System.Net; namespace Oqtane.Controllers { @@ -16,12 +17,14 @@ namespace Oqtane.Controllers private readonly INotificationRepository _notifications; private readonly IUserPermissions _userPermissions; private readonly ILogManager _logger; + private readonly Alias _alias; - public NotificationController(INotificationRepository notifications, IUserPermissions userPermissions, ILogManager logger) + public NotificationController(INotificationRepository notifications, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager) { _notifications = notifications; _userPermissions = userPermissions; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/?siteid=x&type=y&userid=z @@ -30,17 +33,27 @@ namespace Oqtane.Controllers public IEnumerable Get(string siteid, string direction, string userid) { IEnumerable notifications = null; - if (IsAuthorized(int.Parse(userid))) + + int SiteId; + int UserId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId && int.TryParse(userid, out UserId) && IsAuthorized(UserId)) { if (direction == "to") { - notifications = _notifications.GetNotifications(int.Parse(siteid), -1, int.Parse(userid)); + notifications = _notifications.GetNotifications(SiteId, -1, UserId); } else { - notifications = _notifications.GetNotifications(int.Parse(siteid), int.Parse(userid), -1); + notifications = _notifications.GetNotifications(SiteId, UserId, -1); } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Get Attempt {SiteId} {Direction} {UserId}", siteid, direction, userid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + notifications = null; + } + return notifications; } @@ -50,11 +63,16 @@ namespace Oqtane.Controllers public Notification Get(int id) { Notification notification = _notifications.GetNotification(id); - if (!(IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId))) + if (notification != null && notification.SiteId == _alias.SiteId && (IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId))) { - notification = null; + return notification; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Get Attempt {NotificationId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; } - return notification; } // POST api/ @@ -62,11 +80,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Notification Post([FromBody] Notification notification) { - if (IsAuthorized(notification.FromUserId)) + if (ModelState.IsValid && notification.SiteId == _alias.SiteId && IsAuthorized(notification.FromUserId)) { notification = _notifications.AddNotification(notification); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {NotificationId}", notification.NotificationId); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Post Attempt {Notification}", notification); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + notification = null; + } return notification; } @@ -75,11 +99,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Notification Put(int id, [FromBody] Notification notification) { - if (IsAuthorized(notification.FromUserId)) + if (ModelState.IsValid && notification.SiteId == _alias.SiteId && _notifications.GetNotification(notification.NotificationId, false) != null && IsAuthorized(notification.FromUserId)) { notification = _notifications.UpdateNotification(notification); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {NotificationId}", notification.NotificationId); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Put Attempt {Notification}", notification); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + notification = null; + } return notification; } @@ -89,11 +119,16 @@ namespace Oqtane.Controllers public void Delete(int id) { Notification notification = _notifications.GetNotification(id); - if (IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId)) + if (notification != null && notification.SiteId == _alias.SiteId && (IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId))) { _notifications.DeleteNotification(id); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Notification Deleted {NotificationId}", id); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Notification Delete Attempt {NotificationId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } private bool IsAuthorized(int? userid) diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 2ddccb06..80936d3f 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -43,18 +43,30 @@ namespace Oqtane.Controllers [HttpGet] public IEnumerable Get(string siteid) { - List settings = _settings.GetSettings(EntityNames.Page).ToList(); - List pages = new List(); - foreach (Page page in _pages.GetPages(int.Parse(siteid))) + + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { - if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions)) + List settings = _settings.GetSettings(EntityNames.Page).ToList(); + + foreach (Page page in _pages.GetPages(SiteId)) { - page.Settings = settings.Where(item => item.EntityId == page.PageId) - .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); - pages.Add(page); + if (_userPermissions.IsAuthorized(User, PermissionNames.View, page.Permissions)) + { + page.Settings = settings.Where(item => item.EntityId == page.PageId) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); + pages.Add(page); + } } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + pages = null; + } + return pages; } @@ -62,7 +74,7 @@ namespace Oqtane.Controllers [HttpGet("{id}")] public Page Get(int id, string userid) { - Page page; + Page page = null; if (string.IsNullOrEmpty(userid)) { page = _pages.GetPage(id); @@ -79,8 +91,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Page {Page}", page); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Page}", page); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -90,7 +102,7 @@ namespace Oqtane.Controllers public Page Get(string path, int siteid) { Page page = _pages.GetPage(WebUtility.UrlDecode(path), siteid); - if (page != null) + if (page != null && page.SiteId == _alias.SiteId) { if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions)) { @@ -100,14 +112,15 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Page {Page}", page); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Page}", page); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } else { - HttpContext.Response.StatusCode = 404; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Path} for Site {SiteId}", path, siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -117,7 +130,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Page Post([FromBody] Page page) { - if (ModelState.IsValid) + if (ModelState.IsValid && page.SiteId == _alias.SiteId) { string permissions; if (page.ParentId != null) @@ -149,11 +162,17 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Page {Page}", page); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Warning, this, LogFunction.Create, "User Not Authorized To Add Page {Page}", page); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; page = null; } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Post Attempt {Page}", page); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + page = null; + } return page; } @@ -164,7 +183,7 @@ namespace Oqtane.Controllers { Page page = null; Page parent = _pages.GetPage(id); - if (parent != null && parent.IsPersonalizable && _userPermissions.GetUser(User).UserId == int.Parse(userid)) + if (parent != null && parent.SiteId == _alias.SiteId && parent.IsPersonalizable && _userPermissions.GetUser(User).UserId == int.Parse(userid)) { page = new Page(); page.SiteId = parent.SiteId; @@ -219,6 +238,12 @@ namespace Oqtane.Controllers _pageModules.AddPageModule(pagemodule); } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Post Attempt {PageId} By User {UserId}", id, userid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + page = null; + } return page; } @@ -227,7 +252,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public Page Put(int id, [FromBody] Page page) { - if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit)) + if (ModelState.IsValid && page.SiteId == _alias.SiteId && _pages.GetPage(page.PageId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit)) { // preserve page permissions var oldPermissions = _permissionRepository.GetPermissions(EntityNames.Page, page.PageId).ToList(); @@ -281,9 +306,9 @@ namespace Oqtane.Controllers _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Updated {Page}", page); } else - { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Page {Page}", page); - HttpContext.Response.StatusCode = 401; + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Put Attempt {Page}", page); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; page = null; } return page; @@ -307,7 +332,7 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public void Put(int siteid, int pageid, int? parentid) { - if (_userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit)) + if (siteid == _alias.SiteId && siteid == _alias.SiteId && _pages.GetPage(pageid, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit)) { int order = 1; List pages = _pages.GetPages(siteid).ToList(); @@ -325,8 +350,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Page Order {SiteId} {PageId} {ParentId}", siteid, pageid, parentid); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Put Attempt {SiteId} {PageId} {ParentId}", siteid, pageid, parentid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } @@ -336,7 +361,7 @@ namespace Oqtane.Controllers public void Delete(int id) { Page page = _pages.GetPage(id); - if (_userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit)) + if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit)) { _pages.DeletePage(page.PageId); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); @@ -344,8 +369,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete Page {PageId}", page.PageId); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Delete Attempt {PageId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } } diff --git a/Oqtane.Server/Controllers/PageModuleController.cs b/Oqtane.Server/Controllers/PageModuleController.cs index ffb35623..d7015e09 100644 --- a/Oqtane.Server/Controllers/PageModuleController.cs +++ b/Oqtane.Server/Controllers/PageModuleController.cs @@ -8,6 +8,7 @@ using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Security; +using System.Net; namespace Oqtane.Controllers { @@ -15,14 +16,16 @@ namespace Oqtane.Controllers public class PageModuleController : Controller { private readonly IPageModuleRepository _pageModules; + private readonly IPageRepository _pages; private readonly IUserPermissions _userPermissions; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public PageModuleController(IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) + public PageModuleController(IPageModuleRepository pageModules, IPageRepository pages, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { _pageModules = pageModules; + _pages = pages; _userPermissions = userPermissions; _syncManager = syncManager; _logger = logger; @@ -34,14 +37,14 @@ namespace Oqtane.Controllers public PageModule Get(int id) { PageModule pagemodule = _pageModules.GetPageModule(id); - if (_userPermissions.IsAuthorized(User,PermissionNames.View, pagemodule.Module.Permissions)) + if (pagemodule != null && pagemodule.Module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, pagemodule.Module.Permissions)) { return pagemodule; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access PageModule {PageModule}", pagemodule); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Get Attempt {PageModuleId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -51,14 +54,14 @@ namespace Oqtane.Controllers public PageModule Get(int pageid, int moduleid) { PageModule pagemodule = _pageModules.GetPageModule(pageid, moduleid); - if (_userPermissions.IsAuthorized(User,PermissionNames.View, pagemodule.Module.Permissions)) + if (pagemodule != null && pagemodule.Module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, pagemodule.Module.Permissions)) { return pagemodule; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access PageModule {PageModule}", pagemodule); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Get Attempt {PageId} {ModuleId}", pageid, moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -68,7 +71,8 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public PageModule Post([FromBody] PageModule pageModule) { - if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Page, pageModule.PageId, PermissionNames.Edit)) + var page = _pages.GetPage(pageModule.PageId); + if (ModelState.IsValid && page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, pageModule.PageId, PermissionNames.Edit)) { pageModule = _pageModules.AddPageModule(pageModule); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); @@ -76,8 +80,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add PageModule {PageModule}", pageModule); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Post Attempt {PageModule}", pageModule); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; pageModule = null; } return pageModule; @@ -88,7 +92,8 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public PageModule Put(int id, [FromBody] PageModule pageModule) { - if (ModelState.IsValid && _userPermissions.IsAuthorized(User, EntityNames.Module, pageModule.ModuleId, PermissionNames.Edit)) + var page = _pages.GetPage(pageModule.PageId); + if (ModelState.IsValid && page != null && page.SiteId == _alias.SiteId && _pageModules.GetPageModule(pageModule.PageModuleId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Module, pageModule.ModuleId, PermissionNames.Edit)) { pageModule = _pageModules.UpdatePageModule(pageModule); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); @@ -96,8 +101,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update PageModule {PageModule}", pageModule); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Put Attempt {PageModule}", pageModule); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; pageModule = null; } return pageModule; @@ -108,7 +113,8 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Registered)] public void Put(int pageid, string pane) { - if (_userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit)) + var page = _pages.GetPage(pageid); + if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, pageid, PermissionNames.Edit)) { int order = 1; List pagemodules = _pageModules.GetPageModules(pageid, pane).OrderBy(item => item.Order).ToList(); @@ -126,9 +132,9 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Page Module Order {PageId} {Pane}", pageid, pane); - HttpContext.Response.StatusCode = 401; - } + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Put Attempt {PageId} {Pane}", pageid, pane); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } // DELETE api//5 @@ -137,7 +143,7 @@ namespace Oqtane.Controllers public void Delete(int id) { PageModule pagemodule = _pageModules.GetPageModule(id); - if (_userPermissions.IsAuthorized(User, EntityNames.Page, pagemodule.PageId, PermissionNames.Edit)) + if (pagemodule != null && pagemodule.Module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, pagemodule.PageId, PermissionNames.Edit)) { _pageModules.DeletePageModule(id); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); @@ -145,8 +151,8 @@ namespace Oqtane.Controllers } else { - _logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete PageModule {PageModuleId}", id); - HttpContext.Response.StatusCode = 401; + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized PageModule Delete Attempt {PageModuleId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } } diff --git a/Oqtane.Server/Controllers/ProfileController.cs b/Oqtane.Server/Controllers/ProfileController.cs index 60b1de2d..9793b1c6 100644 --- a/Oqtane.Server/Controllers/ProfileController.cs +++ b/Oqtane.Server/Controllers/ProfileController.cs @@ -6,6 +6,7 @@ using Oqtane.Models; using Oqtane.Shared; using Oqtane.Infrastructure; using Oqtane.Repository; +using System.Net; namespace Oqtane.Controllers { @@ -14,25 +15,47 @@ namespace Oqtane.Controllers { private readonly IProfileRepository _profiles; private readonly ILogManager _logger; + private readonly Alias _alias; - public ProfileController(IProfileRepository profiles, ILogManager logger) + public ProfileController(IProfileRepository profiles, ILogManager logger, ITenantManager tenantManager) { _profiles = profiles; _logger = logger; - } + _alias = tenantManager.GetAlias(); + } - // GET: api/?siteid=x - [HttpGet] + // GET: api/?siteid=x + [HttpGet] public IEnumerable Get(string siteid) { - return _profiles.GetProfiles(int.Parse(siteid)); + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) + { + return _profiles.GetProfiles(SiteId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } } // GET api//5 [HttpGet("{id}")] public Profile Get(int id) { - return _profiles.GetProfile(id); + var profile = _profiles.GetProfile(id); + if (profile != null && profile.SiteId == _alias.SiteId) + { + return profile; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Get Attempt {ProfileId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } } // POST api/ @@ -40,11 +63,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public Profile Post([FromBody] Profile profile) { - if (ModelState.IsValid) + if (ModelState.IsValid && profile.SiteId == _alias.SiteId) { profile = _profiles.AddProfile(profile); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Profile Added {Profile}", profile); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Post Attempt {Profile}", profile); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + profile = null; + } return profile; } @@ -53,11 +82,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public Profile Put(int id, [FromBody] Profile profile) { - if (ModelState.IsValid) + if (ModelState.IsValid && profile.SiteId == _alias.SiteId && _profiles.GetProfile(profile.ProfileId, false) != null) { profile = _profiles.UpdateProfile(profile); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Profile Updated {Profile}", profile); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Put Attempt {Profile}", profile); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + profile = null; + } return profile; } @@ -66,8 +101,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public void Delete(int id) { - _profiles.DeleteProfile(id); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Profile Deleted {ProfileId}", id); + var profile = _profiles.GetProfile(id); + if (profile != null && profile.SiteId == _alias.SiteId) + { + _profiles.DeleteProfile(id); + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Profile Deleted {ProfileId}", id); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Profile Delete Attempt {ProfileId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } } } diff --git a/Oqtane.Server/Controllers/RoleController.cs b/Oqtane.Server/Controllers/RoleController.cs index 1b6d9112..aa6c6c29 100644 --- a/Oqtane.Server/Controllers/RoleController.cs +++ b/Oqtane.Server/Controllers/RoleController.cs @@ -6,6 +6,7 @@ using Oqtane.Models; using Oqtane.Shared; using Oqtane.Infrastructure; using Oqtane.Repository; +using System.Net; namespace Oqtane.Controllers { @@ -14,31 +15,53 @@ namespace Oqtane.Controllers { private readonly IRoleRepository _roles; private readonly ILogManager _logger; + private readonly Alias _alias; - public RoleController(IRoleRepository roles, ILogManager logger) + public RoleController(IRoleRepository roles, ILogManager logger, ITenantManager tenantManager) { _roles = roles; _logger = logger; + _alias = tenantManager.GetAlias(); } // GET: api/?siteid=x&global=true/false [HttpGet] - [Authorize(Roles = RoleNames.Registered)] + [Authorize(Roles = RoleNames.Admin)] public IEnumerable Get(string siteid, string global) { - if (string.IsNullOrEmpty(global)) + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { - global = "False"; + if (string.IsNullOrEmpty(global)) + { + global = "False"; + } + return _roles.GetRoles(SiteId, bool.Parse(global)); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; } - return _roles.GetRoles(int.Parse(siteid), bool.Parse(global)); } // GET api//5 [HttpGet("{id}")] - [Authorize(Roles = RoleNames.Registered)] + [Authorize(Roles = RoleNames.Admin)] public Role Get(int id) { - return _roles.GetRole(id); + var role = _roles.GetRole(id); + if (role != null && role.SiteId == _alias.SiteId) + { + return role; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Get Attempt {RoleId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } } // POST api/ @@ -46,11 +69,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public Role Post([FromBody] Role role) { - if (ModelState.IsValid) + if (ModelState.IsValid && role.SiteId == _alias.SiteId) { role = _roles.AddRole(role); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Role Added {Role}", role); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Post Attempt {Role}", role); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + role = null; + } return role; } @@ -59,11 +88,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public Role Put(int id, [FromBody] Role role) { - if (ModelState.IsValid) + if (ModelState.IsValid && role.SiteId == _alias.SiteId && _roles.GetRole(role.RoleId, false) != null) { role = _roles.UpdateRole(role); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Role Updated {Role}", role); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Put Attempt {Role}", role); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + role = null; + } return role; } @@ -73,11 +108,16 @@ namespace Oqtane.Controllers public void Delete(int id) { var role = _roles.GetRole(id); - if (!role.IsSystem) + if (role != null && !role.IsSystem && role.SiteId == _alias.SiteId) { _roles.DeleteRole(id); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Role Deleted {RoleId}", id); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Role Delete Attempt {RoleId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } } } diff --git a/Oqtane.Server/Controllers/SettingController.cs b/Oqtane.Server/Controllers/SettingController.cs index b10a1534..32d0573b 100644 --- a/Oqtane.Server/Controllers/SettingController.cs +++ b/Oqtane.Server/Controllers/SettingController.cs @@ -7,6 +7,7 @@ using System.Linq; using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Repository; +using System.Net; namespace Oqtane.Controllers { @@ -42,7 +43,7 @@ namespace Oqtane.Controllers else { _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Settings {EntityName} {EntityId}", entityname, entityid); - HttpContext.Response.StatusCode = 401; + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } return settings; } @@ -59,7 +60,7 @@ namespace Oqtane.Controllers else { _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Setting {Setting}", setting); - HttpContext.Response.StatusCode = 401; + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } } @@ -80,7 +81,7 @@ namespace Oqtane.Controllers else { _logger.Log(LogLevel.Error, this, LogFunction.Create, "User Not Authorized To Add Setting {Setting}", setting); - HttpContext.Response.StatusCode = 401; + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; setting = null; } return setting; @@ -102,7 +103,7 @@ namespace Oqtane.Controllers else { _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update Setting {Setting}", setting); - HttpContext.Response.StatusCode = 401; + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; setting = null; } return setting; @@ -125,7 +126,7 @@ namespace Oqtane.Controllers else { _logger.Log(LogLevel.Error, this, LogFunction.Delete, "User Not Authorized To Delete Setting {Setting}", setting); - HttpContext.Response.StatusCode = 401; + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index e40e9065..8b6cba5c 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -7,6 +7,7 @@ using System.Linq; using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Repository; +using System.Net; namespace Oqtane.Controllers { @@ -38,7 +39,17 @@ namespace Oqtane.Controllers [HttpGet("{id}")] public Site Get(int id) { - return _sites.GetSite(id); + var site = _sites.GetSite(id); + if (site.SiteId == _alias.SiteId) + { + return site; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Get Attempt {SiteId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } } // POST api/ @@ -72,12 +83,18 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public Site Put(int id, [FromBody] Site site) { - if (ModelState.IsValid) + if (ModelState.IsValid && site.SiteId == _alias.SiteId && site.TenantId == _alias.TenantId && _sites.GetSite(site.SiteId, false) != null) { site = _sites.UpdateSite(site); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId); _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Update, "Site Updated {Site}", site); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Put Attempt {Site}", site); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + site = null; + } return site; } @@ -86,8 +103,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Host)] public void Delete(int id) { - _sites.DeleteSite(id); - _logger.Log(id, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", id); + var site = _sites.GetSite(id); + if (site != null && site.SiteId == _alias.SiteId) + { + _sites.DeleteSite(id); + _logger.Log(id, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", id); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Delete Attempt {SiteId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } } } diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index 1d1434bf..8f42d644 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -53,26 +53,46 @@ namespace Oqtane.Controllers [Authorize] public User Get(int id, string siteid) { - User user = _users.GetUser(id); - if (user != null) + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { - user.SiteId = int.Parse(siteid); - user.Roles = GetUserRoles(user.UserId, user.SiteId); + User user = _users.GetUser(id); + if (user != null) + { + user.SiteId = int.Parse(siteid); + user.Roles = GetUserRoles(user.UserId, user.SiteId); + } + return Filter(user); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Get Attempt {UserId} {SiteId}", id, siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; } - return Filter(user); } // GET api//name/x?siteid=x [HttpGet("name/{name}")] public User Get(string name, string siteid) { - User user = _users.GetUser(name); - if (user != null) + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { - user.SiteId = int.Parse(siteid); - user.Roles = GetUserRoles(user.UserId, user.SiteId); + User user = _users.GetUser(name); + if (user != null) + { + user.SiteId = int.Parse(siteid); + user.Roles = GetUserRoles(user.UserId, user.SiteId); + } + return Filter(user); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Get Attempt {Username} {SiteId}", name, siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; } - return Filter(user); } private User Filter(User user) @@ -102,13 +122,18 @@ namespace Oqtane.Controllers [HttpPost] public async Task Post([FromBody] User user) { - if (ModelState.IsValid) + if (ModelState.IsValid && user.SiteId == _alias.SiteId) { - var newUser = await CreateUser(user); - return newUser; + var User = await CreateUser(user); + return User; + } + else + { + user.Password = ""; // remove sensitive information + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Post Attempt {User}", user); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; } - - return null; } private async Task CreateUser(User user) @@ -230,30 +255,28 @@ namespace Oqtane.Controllers [Authorize] public async Task Put(int id, [FromBody] User user) { - if (ModelState.IsValid) + if (ModelState.IsValid && user.SiteId == _alias.SiteId && _users.GetUser(user.UserId, false) != null && (User.IsInRole(RoleNames.Admin) || User.Identity.Name == user.Username)) { - if (User.IsInRole(RoleNames.Admin) || User.Identity.Name == user.Username) + if (user.Password != "") { - if (user.Password != "") + IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username); + if (identityuser != null) { - IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username); - if (identityuser != null) - { - identityuser.PasswordHash = _identityUserManager.PasswordHasher.HashPassword(identityuser, user.Password); - await _identityUserManager.UpdateAsync(identityuser); - } + identityuser.PasswordHash = _identityUserManager.PasswordHasher.HashPassword(identityuser, user.Password); + await _identityUserManager.UpdateAsync(identityuser); } - user = _users.UpdateUser(user); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, user.UserId); - user.Password = ""; // remove sensitive information - _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user); - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Update, "User Not Authorized To Update User {User}", user); - HttpContext.Response.StatusCode = 401; - user = null; } + user = _users.UpdateUser(user); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, user.UserId); + user.Password = ""; // remove sensitive information + _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user); + } + else + { + user.Password = ""; // remove sensitive information + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Post Attempt {User}", user); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + user = null; } return user; } @@ -263,18 +286,19 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public async Task Delete(int id, string siteid) { + int SiteId; User user = _users.GetUser(id); - if (user != null) + if (user != null && int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) { // remove user roles for site - foreach (UserRole userrole in _userRoles.GetUserRoles(user.UserId, Int32.Parse(siteid)).ToList()) + foreach (UserRole userrole in _userRoles.GetUserRoles(user.UserId, SiteId).ToList()) { _userRoles.DeleteUserRole(userrole.UserRoleId); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userrole); } // remove user folder for site - var folder = _folders.GetFolder(Int32.Parse(siteid), Utilities.PathCombine("Users", user.UserId.ToString(), Path.DirectorySeparatorChar.ToString())); + var folder = _folders.GetFolder(SiteId, Utilities.PathCombine("Users", user.UserId.ToString(), Path.DirectorySeparatorChar.ToString())); if (folder != null) { if (Directory.Exists(_folders.GetFolderPath(folder))) @@ -307,6 +331,11 @@ namespace Oqtane.Controllers } } } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Delete Attempt {UserId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } // POST api//login diff --git a/Oqtane.Server/Controllers/UserRoleController.cs b/Oqtane.Server/Controllers/UserRoleController.cs index 99b1253f..4d1ac5bc 100644 --- a/Oqtane.Server/Controllers/UserRoleController.cs +++ b/Oqtane.Server/Controllers/UserRoleController.cs @@ -7,6 +7,7 @@ using Oqtane.Shared; using Oqtane.Infrastructure; using Oqtane.Repository; using System.Linq; +using System.Net; namespace Oqtane.Controllers { @@ -33,7 +34,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public IEnumerable Get(string siteid) { - return _userRoles.GetUserRoles(int.Parse(siteid)); + int SiteId; + if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId) + { + return _userRoles.GetUserRoles(SiteId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UserRole Get Attempt {SiteId}", siteid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } } // GET api//5 @@ -41,7 +52,17 @@ namespace Oqtane.Controllers [Authorize(Roles = RoleNames.Admin)] public UserRole Get(int id) { - return _userRoles.GetUserRole(id); + var userrole = _userRoles.GetUserRole(id); + if (userrole != null && userrole.Role.SiteId == _alias.SiteId) + { + return userrole; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Role Get Attempt {UserRoleId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } } // POST api/ @@ -50,7 +71,7 @@ namespace Oqtane.Controllers public UserRole Post([FromBody] UserRole userRole) { var role = _roles.GetRole(userRole.RoleId); - if (ModelState.IsValid && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host)) + if (ModelState.IsValid && role != null && role.SiteId == _alias.SiteId && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host)) { if (role.Name == RoleNames.Host) { @@ -64,6 +85,12 @@ namespace Oqtane.Controllers _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UserRole Post Attempt {UserRole}", userRole); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + userRole = null; + } return userRole; } @@ -73,12 +100,18 @@ namespace Oqtane.Controllers public UserRole Put(int id, [FromBody] UserRole userRole) { var role = _roles.GetRole(userRole.RoleId); - if (ModelState.IsValid && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host)) + if (ModelState.IsValid && role != null && role.SiteId == _alias.SiteId && _userRoles.GetUserRole(userRole.UserRoleId, false) != null && (User.IsInRole(RoleNames.Host) || role.Name != RoleNames.Host)) { userRole = _userRoles.UpdateUserRole(userRole); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId); _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Role Updated {UserRole}", userRole); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Role Put Attempt {UserRole}", userRole); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + userRole = null; + } return userRole; } @@ -88,7 +121,7 @@ namespace Oqtane.Controllers public void Delete(int id) { UserRole userRole = _userRoles.GetUserRole(id); - if (User.IsInRole(RoleNames.Host) || userRole.Role.Name != RoleNames.Host) + if (userRole != null && userRole.Role.SiteId == _alias.SiteId && (User.IsInRole(RoleNames.Host) || userRole.Role.Name != RoleNames.Host)) { _userRoles.DeleteUserRole(id); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userRole); @@ -106,6 +139,11 @@ namespace Oqtane.Controllers _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId); } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Role Delete Attempt {UserRoleId}", id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } } } } diff --git a/Oqtane.Server/Repository/FileRepository.cs b/Oqtane.Server/Repository/FileRepository.cs index 9c170523..1c6179f6 100644 --- a/Oqtane.Server/Repository/FileRepository.cs +++ b/Oqtane.Server/Repository/FileRepository.cs @@ -63,12 +63,11 @@ namespace Oqtane.Repository File file; if (tracking) { - file = _db.File.Where(item => item.FileId == fileId).Include(item => item.Folder).FirstOrDefault(); - + file = _db.File.Include(item => item.Folder).FirstOrDefault(item => item.FileId == fileId); } else { - file = _db.File.AsNoTracking().Where(item => item.FileId == fileId).Include(item => item.Folder).FirstOrDefault(); + file = _db.File.AsNoTracking().Include(item => item.Folder).FirstOrDefault(item => item.FileId == fileId); } if (file != null) { diff --git a/Oqtane.Server/Repository/FolderRepository.cs b/Oqtane.Server/Repository/FolderRepository.cs index 13797658..7059f389 100644 --- a/Oqtane.Server/Repository/FolderRepository.cs +++ b/Oqtane.Server/Repository/FolderRepository.cs @@ -61,7 +61,7 @@ namespace Oqtane.Repository Folder folder; if (tracking) { - folder = _db.Folder.Where(item => item.FolderId == folderId).FirstOrDefault(); + folder = _db.Folder.Find(folderId); } else { diff --git a/Oqtane.Server/Repository/Interfaces/IModuleRepository.cs b/Oqtane.Server/Repository/Interfaces/IModuleRepository.cs index 2ef4185d..08923ecd 100644 --- a/Oqtane.Server/Repository/Interfaces/IModuleRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IModuleRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -9,6 +9,7 @@ namespace Oqtane.Repository Module AddModule(Module module); Module UpdateModule(Module module); Module GetModule(int moduleId); + Module GetModule(int moduleId, bool tracking); void DeleteModule(int moduleId); string ExportModule(int moduleId); bool ImportModule(int moduleId, string content); diff --git a/Oqtane.Server/Repository/Interfaces/INotificationRepository.cs b/Oqtane.Server/Repository/Interfaces/INotificationRepository.cs index ef53bc3a..5dfb81b6 100644 --- a/Oqtane.Server/Repository/Interfaces/INotificationRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/INotificationRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -9,6 +9,7 @@ namespace Oqtane.Repository Notification AddNotification(Notification notification); Notification UpdateNotification(Notification notification); Notification GetNotification(int notificationId); + Notification GetNotification(int notificationId, bool tracking); void DeleteNotification(int notificationId); } } diff --git a/Oqtane.Server/Repository/Interfaces/IPageModuleRepository.cs b/Oqtane.Server/Repository/Interfaces/IPageModuleRepository.cs index 181fb629..6085fcc2 100644 --- a/Oqtane.Server/Repository/Interfaces/IPageModuleRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IPageModuleRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -10,6 +10,7 @@ namespace Oqtane.Repository PageModule AddPageModule(PageModule pageModule); PageModule UpdatePageModule(PageModule pageModule); PageModule GetPageModule(int pageModuleId); + PageModule GetPageModule(int pageModuleId, bool tracking); PageModule GetPageModule(int pageId, int moduleId); void DeletePageModule(int pageModuleId); } diff --git a/Oqtane.Server/Repository/Interfaces/IPageRepository.cs b/Oqtane.Server/Repository/Interfaces/IPageRepository.cs index 6db92dba..98ce2ef3 100644 --- a/Oqtane.Server/Repository/Interfaces/IPageRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IPageRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -9,6 +9,7 @@ namespace Oqtane.Repository Page AddPage(Page page); Page UpdatePage(Page page); Page GetPage(int pageId); + Page GetPage(int pageId, bool tracking); Page GetPage(int pageId, int userId); Page GetPage(string path, int siteId); void DeletePage(int pageId); diff --git a/Oqtane.Server/Repository/Interfaces/IProfileRepository.cs b/Oqtane.Server/Repository/Interfaces/IProfileRepository.cs index c9b4f34b..95405c96 100644 --- a/Oqtane.Server/Repository/Interfaces/IProfileRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IProfileRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -9,6 +9,7 @@ namespace Oqtane.Repository Profile AddProfile(Profile profile); Profile UpdateProfile(Profile profile); Profile GetProfile(int profileId); + Profile GetProfile(int profileId, bool tracking); void DeleteProfile(int profileId); } } diff --git a/Oqtane.Server/Repository/Interfaces/IRoleRepository.cs b/Oqtane.Server/Repository/Interfaces/IRoleRepository.cs index 35f9315f..1b2ea0e4 100644 --- a/Oqtane.Server/Repository/Interfaces/IRoleRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IRoleRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -10,6 +10,7 @@ namespace Oqtane.Repository Role AddRole(Role role); Role UpdateRole(Role role); Role GetRole(int roleId); + Role GetRole(int roleId, bool tracking); void DeleteRole(int roleId); } } diff --git a/Oqtane.Server/Repository/Interfaces/ISiteRepository.cs b/Oqtane.Server/Repository/Interfaces/ISiteRepository.cs index c8cfec23..8172efff 100644 --- a/Oqtane.Server/Repository/Interfaces/ISiteRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/ISiteRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -9,6 +9,7 @@ namespace Oqtane.Repository Site AddSite(Site site); Site UpdateSite(Site site); Site GetSite(int siteId); + Site GetSite(int siteId, bool tracking); void DeleteSite(int siteId); void CreatePages(Site site, List pageTemplates); } diff --git a/Oqtane.Server/Repository/Interfaces/IUserRepository.cs b/Oqtane.Server/Repository/Interfaces/IUserRepository.cs index be646e56..89a25bca 100644 --- a/Oqtane.Server/Repository/Interfaces/IUserRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IUserRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Oqtane.Models; namespace Oqtane.Repository @@ -9,6 +9,7 @@ namespace Oqtane.Repository User AddUser(User user); User UpdateUser(User user); User GetUser(int userId); + User GetUser(int userId, bool tracking); User GetUser(string username); void DeleteUser(int userId); } diff --git a/Oqtane.Server/Repository/Interfaces/IUserRoleRepository.cs b/Oqtane.Server/Repository/Interfaces/IUserRoleRepository.cs index b26eb5dc..0c4a2290 100644 --- a/Oqtane.Server/Repository/Interfaces/IUserRoleRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/IUserRoleRepository.cs @@ -10,6 +10,7 @@ namespace Oqtane.Repository UserRole AddUserRole(UserRole userRole); UserRole UpdateUserRole(UserRole userRole); UserRole GetUserRole(int userRoleId); + UserRole GetUserRole(int userRoleId, bool tracking); void DeleteUserRole(int userRoleId); void DeleteUserRoles(int userId); } diff --git a/Oqtane.Server/Repository/ModuleRepository.cs b/Oqtane.Server/Repository/ModuleRepository.cs index 9d83351a..90710bd8 100644 --- a/Oqtane.Server/Repository/ModuleRepository.cs +++ b/Oqtane.Server/Repository/ModuleRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; @@ -48,12 +48,24 @@ namespace Oqtane.Repository public Module GetModule(int moduleId) { - Module module = _db.Module.Find(moduleId); + return GetModule(moduleId, true); + } + + public Module GetModule(int moduleId, bool tracking) + { + Module module; + if (tracking) + { + module = _db.Module.Find(moduleId); + } + else + { + module = _db.Module.AsNoTracking().FirstOrDefault(item => item.ModuleId == moduleId); + } if (module != null) { module.Permissions = _permissions.GetPermissionString("Module", module.ModuleId); } - return module; } diff --git a/Oqtane.Server/Repository/NotificationRepository.cs b/Oqtane.Server/Repository/NotificationRepository.cs index 38ec8559..aa05bf17 100644 --- a/Oqtane.Server/Repository/NotificationRepository.cs +++ b/Oqtane.Server/Repository/NotificationRepository.cs @@ -45,10 +45,21 @@ namespace Oqtane.Repository _db.SaveChanges(); return notification; } - public Notification GetNotification(int notificationId) { - return _db.Notification.Find(notificationId); + return GetNotification(notificationId, true); + } + + public Notification GetNotification(int notificationId, bool tracking) + { + if (tracking) + { + return _db.Notification.Find(notificationId); + } + else + { + return _db.Notification.AsNoTracking().FirstOrDefault(item => item.NotificationId == notificationId); + } } public void DeleteNotification(int notificationId) diff --git a/Oqtane.Server/Repository/PageModuleRepository.cs b/Oqtane.Server/Repository/PageModuleRepository.cs index e78abb07..07d39801 100644 --- a/Oqtane.Server/Repository/PageModuleRepository.cs +++ b/Oqtane.Server/Repository/PageModuleRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using Oqtane.Extensions; @@ -69,8 +69,22 @@ namespace Oqtane.Repository public PageModule GetPageModule(int pageModuleId) { - PageModule pagemodule = _db.PageModule.Include(item => item.Module) // eager load modules - .SingleOrDefault(item => item.PageModuleId == pageModuleId); + return GetPageModule(pageModuleId, true); + } + + public PageModule GetPageModule(int pageModuleId, bool tracking) + { + PageModule pagemodule; + if (tracking) + { + pagemodule = _db.PageModule.Include(item => item.Module) // eager load modules + .FirstOrDefault(item => item.PageModuleId == pageModuleId); + } + else + { + pagemodule = _db.PageModule.AsNoTracking().Include(item => item.Module) // eager load modules + .FirstOrDefault(item => item.PageModuleId == pageModuleId); + } if (pagemodule != null) { pagemodule.Module.Permissions = _permissions.GetPermissionString("Module", pagemodule.ModuleId); diff --git a/Oqtane.Server/Repository/PageRepository.cs b/Oqtane.Server/Repository/PageRepository.cs index 9db59dc2..ac89a444 100644 --- a/Oqtane.Server/Repository/PageRepository.cs +++ b/Oqtane.Server/Repository/PageRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using Oqtane.Extensions; @@ -49,7 +49,21 @@ namespace Oqtane.Repository public Page GetPage(int pageId) { - Page page = _db.Page.Find(pageId); + return GetPage(pageId, true); + } + + public Page GetPage(int pageId, bool tracking) + { + Page page; + if (tracking) + { + page = _db.Page.Find(pageId); + + } + else + { + page = _db.Page.AsNoTracking().FirstOrDefault(item => item.PageId == pageId); + } if (page != null) { page.Permissions = _permissions.GetPermissionString(EntityNames.Page, page.PageId); diff --git a/Oqtane.Server/Repository/ProfileRepository.cs b/Oqtane.Server/Repository/ProfileRepository.cs index 8577ea78..3109fa3c 100644 --- a/Oqtane.Server/Repository/ProfileRepository.cs +++ b/Oqtane.Server/Repository/ProfileRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using Oqtane.Models; @@ -35,7 +35,19 @@ namespace Oqtane.Repository public Profile GetProfile(int profileId) { - return _db.Profile.Find(profileId); + return GetProfile(profileId, true); + } + + public Profile GetProfile(int profileId, bool tracking) + { + if (tracking) + { + return _db.Profile.Find(profileId); + } + else + { + return _db.Profile.AsNoTracking().FirstOrDefault(item => item.ProfileId == profileId); + } } public void DeleteProfile(int profileId) diff --git a/Oqtane.Server/Repository/RoleRepository.cs b/Oqtane.Server/Repository/RoleRepository.cs index b8afb4a4..c50ead27 100644 --- a/Oqtane.Server/Repository/RoleRepository.cs +++ b/Oqtane.Server/Repository/RoleRepository.cs @@ -49,7 +49,19 @@ namespace Oqtane.Repository public Role GetRole(int roleId) { - return _db.Role.Find(roleId); + return GetRole(roleId, true); + } + + public Role GetRole(int roleId, bool tracking) + { + if (tracking) + { + return _db.Role.Find(roleId); + } + else + { + return _db.Role.AsNoTracking().FirstOrDefault(item => item.RoleId == roleId); + } } public void DeleteRole(int roleId) diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 7d45e691..9487f391 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -620,7 +620,19 @@ namespace Oqtane.Repository public Site GetSite(int siteId) { - return _db.Site.Find(siteId); + return GetSite(siteId, true); + } + + public Site GetSite(int siteId, bool tracking) + { + if (tracking) + { + return _db.Site.Find(siteId); + } + else + { + return _db.Site.AsNoTracking().FirstOrDefault(item => item.SiteId == siteId); + } } public void DeleteSite(int siteId) diff --git a/Oqtane.Server/Repository/UserRepository.cs b/Oqtane.Server/Repository/UserRepository.cs index a9e51afe..2a71e980 100644 --- a/Oqtane.Server/Repository/UserRepository.cs +++ b/Oqtane.Server/Repository/UserRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; using Oqtane.Models; @@ -35,7 +35,19 @@ namespace Oqtane.Repository public User GetUser(int userId) { - return _db.User.Find(userId); + return GetUser(userId, true); + } + + public User GetUser(int userId, bool tracking) + { + if (tracking) + { + return _db.User.Find(userId); + } + else + { + return _db.User.AsNoTracking().FirstOrDefault(item => item.UserId == userId); + } } public User GetUser(string username) diff --git a/Oqtane.Server/Repository/UserRoleRepository.cs b/Oqtane.Server/Repository/UserRoleRepository.cs index d62156f5..8eef5221 100644 --- a/Oqtane.Server/Repository/UserRoleRepository.cs +++ b/Oqtane.Server/Repository/UserRoleRepository.cs @@ -46,10 +46,25 @@ namespace Oqtane.Repository public UserRole GetUserRole(int userRoleId) { - return _db.UserRole - .Include(item => item.Role) // eager load roles - .Include(item => item.User) // eager load users - .SingleOrDefault(item => item.UserRoleId == userRoleId); + return GetUserRole(userRoleId, true); + } + + public UserRole GetUserRole(int userRoleId, bool tracking) + { + if (tracking) + { + return _db.UserRole + .Include(item => item.Role) // eager load roles + .Include(item => item.User) // eager load users + .FirstOrDefault(item => item.UserRoleId == userRoleId); + } + else + { + return _db.UserRole.AsNoTracking() + .Include(item => item.Role) // eager load roles + .Include(item => item.User) // eager load users + .FirstOrDefault(item => item.UserRoleId == userRoleId); + } } public void DeleteUserRole(int userRoleId) diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 061b78bc..01a8b331 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -165,7 +166,7 @@ namespace Oqtane options.Cookie.HttpOnly = false; options.Events.OnRedirectToLogin = context => { - context.Response.StatusCode = 401; + context.Response.StatusCode = (int)HttpStatusCode.Forbidden; return Task.CompletedTask; }; options.Events.OnValidatePrincipal = PrincipalValidator.ValidateAsync;