diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index b8ee0e97c4..0e9a9a3862 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -12,5 +12,10 @@ public const string MacroContentCacheKey = "macroContent_"; // used in MacroRenderers public const string MacroFromAliasCacheKey = "macroFromAlias_"; + + public const string UserAllContentStartNodesPrefix = "AllContentStartNodes"; + public const string UserAllMediaStartNodesPrefix = "AllMediaStartNodes"; + public const string UserMediaStartNodePathsPrefix = "MediaStartNodePaths"; + public const string UserContentStartNodePathsPrefix = "ContentStartNodePaths"; } } diff --git a/src/Umbraco.Core/Models/Identity/IdentityMapDefinition.cs b/src/Umbraco.Core/Models/Identity/IdentityMapDefinition.cs index 57e1c9ee5c..47d33f3014 100644 --- a/src/Umbraco.Core/Models/Identity/IdentityMapDefinition.cs +++ b/src/Umbraco.Core/Models/Identity/IdentityMapDefinition.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Mapping; using Umbraco.Core.Models.Membership; @@ -11,7 +12,9 @@ namespace Umbraco.Core.Models.Identity private readonly ILocalizedTextService _textService; private readonly IEntityService _entityService; private readonly IGlobalSettings _globalSettings; + private readonly AppCaches _appCaches; + [Obsolete("Use constructor specifying all dependencies")] public IdentityMapDefinition(ILocalizedTextService textService, IEntityService entityService, IGlobalSettings globalSettings) { _textService = textService; @@ -19,6 +22,14 @@ namespace Umbraco.Core.Models.Identity _globalSettings = globalSettings; } + public IdentityMapDefinition(ILocalizedTextService textService, IEntityService entityService, IGlobalSettings globalSettings, AppCaches appCaches) + { + _textService = textService; + _entityService = entityService; + _globalSettings = globalSettings; + _appCaches = appCaches; + } + public void DefineMaps(UmbracoMapper mapper) { mapper.Define( @@ -46,8 +57,8 @@ namespace Umbraco.Core.Models.Identity target.Groups = source.Groups.ToArray(); */ - target.CalculatedMediaStartNodeIds = source.CalculateMediaStartNodeIds(_entityService); - target.CalculatedContentStartNodeIds = source.CalculateContentStartNodeIds(_entityService); + target.CalculatedMediaStartNodeIds = source.CalculateMediaStartNodeIds(_entityService, _appCaches); + target.CalculatedContentStartNodeIds = source.CalculateContentStartNodeIds(_entityService, _appCaches); target.Email = source.Email; target.UserName = source.Username; target.LastPasswordChangeDateUtc = source.LastPasswordChangeDate.ToUniversalTime(); diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 3d071b0a18..dc39463925 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Runtime.Serialization; using Umbraco.Core.Composing; @@ -384,11 +385,10 @@ namespace Umbraco.Core.Models.Membership #endregion - /// - /// This is used as an internal cache for this entity - specifically for calculating start nodes so we don't re-calculated all of the time - /// [IgnoreDataMember] [DoNotClone] + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("This should not be used, it's currently used for only a single edge case - should probably be removed for netcore")] internal IDictionary AdditionalData { get @@ -402,6 +402,8 @@ namespace Umbraco.Core.Models.Membership [IgnoreDataMember] [DoNotClone] + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("Not used, will be removed in future versions")] internal object AdditionalDataLock => _additionalDataLock; protected override void PerformDeepClone(object clone) diff --git a/src/Umbraco.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs index 5be66bac47..fdb833a821 100644 --- a/src/Umbraco.Core/Models/UserExtensions.cs +++ b/src/Umbraco.Core/Models/UserExtensions.cs @@ -150,48 +150,40 @@ namespace Umbraco.Core.Models } } - internal static bool HasContentRootAccess(this IUser user, IEntityService entityService) - { - return ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent); - } + internal static bool HasContentRootAccess(this IUser user, IEntityService entityService, AppCaches appCaches) + => ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateContentStartNodeIds(entityService, appCaches), Constants.System.RecycleBinContent); - internal static bool HasContentBinAccess(this IUser user, IEntityService entityService) - { - return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinContentString, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent); - } + internal static bool HasContentBinAccess(this IUser user, IEntityService entityService, AppCaches appCaches) + => ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinContentString, user.CalculateContentStartNodeIds(entityService, appCaches), Constants.System.RecycleBinContent); - internal static bool HasMediaRootAccess(this IUser user, IEntityService entityService) - { - return ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia); - } + internal static bool HasMediaRootAccess(this IUser user, IEntityService entityService, AppCaches appCaches) + => ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateMediaStartNodeIds(entityService, appCaches), Constants.System.RecycleBinMedia); - internal static bool HasMediaBinAccess(this IUser user, IEntityService entityService) - { - return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinMediaString, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia); - } + internal static bool HasMediaBinAccess(this IUser user, IEntityService entityService, AppCaches appCaches) + => ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinMediaString, user.CalculateMediaStartNodeIds(entityService, appCaches), Constants.System.RecycleBinMedia); - internal static bool HasPathAccess(this IUser user, IContent content, IEntityService entityService) + internal static bool HasPathAccess(this IUser user, IContent content, IEntityService entityService, AppCaches appCaches) { if (content == null) throw new ArgumentNullException(nameof(content)); - return ContentPermissionsHelper.HasPathAccess(content.Path, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent); + return ContentPermissionsHelper.HasPathAccess(content.Path, user.CalculateContentStartNodeIds(entityService, appCaches), Constants.System.RecycleBinContent); } - internal static bool HasPathAccess(this IUser user, IMedia media, IEntityService entityService) + internal static bool HasPathAccess(this IUser user, IMedia media, IEntityService entityService, AppCaches appCaches) { if (media == null) throw new ArgumentNullException(nameof(media)); - return ContentPermissionsHelper.HasPathAccess(media.Path, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia); + return ContentPermissionsHelper.HasPathAccess(media.Path, user.CalculateMediaStartNodeIds(entityService, appCaches), Constants.System.RecycleBinMedia); } - internal static bool HasContentPathAccess(this IUser user, IUmbracoEntity entity, IEntityService entityService) + internal static bool HasContentPathAccess(this IUser user, IUmbracoEntity entity, IEntityService entityService, AppCaches appCaches) { if (entity == null) throw new ArgumentNullException(nameof(entity)); - return ContentPermissionsHelper.HasPathAccess(entity.Path, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent); + return ContentPermissionsHelper.HasPathAccess(entity.Path, user.CalculateContentStartNodeIds(entityService, appCaches), Constants.System.RecycleBinContent); } - internal static bool HasMediaPathAccess(this IUser user, IUmbracoEntity entity, IEntityService entityService) + internal static bool HasMediaPathAccess(this IUser user, IUmbracoEntity entity, IEntityService entityService, AppCaches appCaches) { if (entity == null) throw new ArgumentNullException(nameof(entity)); - return ContentPermissionsHelper.HasPathAccess(entity.Path, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia); + return ContentPermissionsHelper.HasPathAccess(entity.Path, user.CalculateMediaStartNodeIds(entityService, appCaches), Constants.System.RecycleBinMedia); } /// @@ -204,84 +196,92 @@ namespace Umbraco.Core.Models return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.SensitiveDataGroupAlias); } - // calc. start nodes, combining groups' and user's, and excluding what's in the bin + [Obsolete("Use the overload specifying all parameters instead")] public static int[] CalculateContentStartNodeIds(this IUser user, IEntityService entityService) - { - const string cacheKey = "AllContentStartNodes"; - //try to look them up from cache so we don't recalculate - var valuesInUserCache = FromUserCache(user, cacheKey); - if (valuesInUserCache != null) return valuesInUserCache; + => CalculateContentStartNodeIds(user, entityService, Current.AppCaches); - var gsn = user.Groups.Where(x => x.StartContentId.HasValue).Select(x => x.StartContentId.Value).Distinct().ToArray(); - var usn = user.StartContentIds; - var vals = CombineStartNodes(UmbracoObjectTypes.Document, gsn, usn, entityService); - ToUserCache(user, cacheKey, vals); - return vals; + /// + /// Calculate start nodes, combining groups' and user's, and excluding what's in the bin + /// + /// + /// + /// + /// + public static int[] CalculateContentStartNodeIds(this IUser user, IEntityService entityService, AppCaches appCaches) + { + var cacheKey = CacheKeys.UserAllContentStartNodesPrefix + user.Id; + var runtimeCache = appCaches.IsolatedCaches.GetOrCreate(); + var result = runtimeCache.GetCacheItem(cacheKey, () => + { + var gsn = user.Groups.Where(x => x.StartContentId.HasValue).Select(x => x.StartContentId.Value).Distinct().ToArray(); + var usn = user.StartContentIds; + var vals = CombineStartNodes(UmbracoObjectTypes.Document, gsn, usn, entityService); + return vals; + }, TimeSpan.FromMinutes(2), true); + + return result; } - // calc. start nodes, combining groups' and user's, and excluding what's in the bin + [Obsolete("Use the overload specifying all parameters instead")] public static int[] CalculateMediaStartNodeIds(this IUser user, IEntityService entityService) - { - const string cacheKey = "AllMediaStartNodes"; - //try to look them up from cache so we don't recalculate - var valuesInUserCache = FromUserCache(user, cacheKey); - if (valuesInUserCache != null) return valuesInUserCache; + => CalculateMediaStartNodeIds(user, entityService, Current.AppCaches); - var gsn = user.Groups.Where(x => x.StartMediaId.HasValue).Select(x => x.StartMediaId.Value).Distinct().ToArray(); - var usn = user.StartMediaIds; - var vals = CombineStartNodes(UmbracoObjectTypes.Media, gsn, usn, entityService); - ToUserCache(user, cacheKey, vals); - return vals; + /// + /// Calculate start nodes, combining groups' and user's, and excluding what's in the bin + /// + /// + /// + /// + /// + public static int[] CalculateMediaStartNodeIds(this IUser user, IEntityService entityService, AppCaches appCaches) + { + var cacheKey = CacheKeys.UserAllMediaStartNodesPrefix + user.Id; + var runtimeCache = appCaches.IsolatedCaches.GetOrCreate(); + var result = runtimeCache.GetCacheItem(cacheKey, () => + { + var gsn = user.Groups.Where(x => x.StartMediaId.HasValue).Select(x => x.StartMediaId.Value).Distinct().ToArray(); + var usn = user.StartMediaIds; + var vals = CombineStartNodes(UmbracoObjectTypes.Media, gsn, usn, entityService); + return vals; + }, TimeSpan.FromMinutes(2), true); + + return result; } + [Obsolete("Use the overload specifying all parameters instead")] public static string[] GetMediaStartNodePaths(this IUser user, IEntityService entityService) - { - const string cacheKey = "MediaStartNodePaths"; - //try to look them up from cache so we don't recalculate - var valuesInUserCache = FromUserCache(user, cacheKey); - if (valuesInUserCache != null) return valuesInUserCache; + => GetMediaStartNodePaths(user, entityService, Current.AppCaches); - var startNodeIds = user.CalculateMediaStartNodeIds(entityService); - var vals = entityService.GetAllPaths(UmbracoObjectTypes.Media, startNodeIds).Select(x => x.Path).ToArray(); - ToUserCache(user, cacheKey, vals); - return vals; + public static string[] GetMediaStartNodePaths(this IUser user, IEntityService entityService, AppCaches appCaches) + { + var cacheKey = CacheKeys.UserMediaStartNodePathsPrefix + user.Id; + var runtimeCache = appCaches.IsolatedCaches.GetOrCreate(); + var result = runtimeCache.GetCacheItem(cacheKey, () => + { + var startNodeIds = user.CalculateMediaStartNodeIds(entityService, appCaches); + var vals = entityService.GetAllPaths(UmbracoObjectTypes.Media, startNodeIds).Select(x => x.Path).ToArray(); + return vals; + }, TimeSpan.FromMinutes(2), true); + + return result; } + [Obsolete("Use the overload specifying all parameters instead")] public static string[] GetContentStartNodePaths(this IUser user, IEntityService entityService) + => GetContentStartNodePaths(user, entityService, Current.AppCaches); + + public static string[] GetContentStartNodePaths(this IUser user, IEntityService entityService, AppCaches appCaches) { - const string cacheKey = "ContentStartNodePaths"; - //try to look them up from cache so we don't recalculate - var valuesInUserCache = FromUserCache(user, cacheKey); - if (valuesInUserCache != null) return valuesInUserCache; - - var startNodeIds = user.CalculateContentStartNodeIds(entityService); - var vals = entityService.GetAllPaths(UmbracoObjectTypes.Document, startNodeIds).Select(x => x.Path).ToArray(); - ToUserCache(user, cacheKey, vals); - return vals; - } - - private static T FromUserCache(IUser user, string cacheKey) - where T: class - { - if (!(user is User entityUser)) return null; - - lock (entityUser.AdditionalDataLock) + var cacheKey = CacheKeys.UserContentStartNodePathsPrefix + user.Id; + var runtimeCache = appCaches.IsolatedCaches.GetOrCreate(); + var result = runtimeCache.GetCacheItem(cacheKey, () => { - return entityUser.AdditionalData.TryGetValue(cacheKey, out var allContentStartNodes) - ? allContentStartNodes as T - : null; - } - } + var startNodeIds = user.CalculateContentStartNodeIds(entityService, appCaches); + var vals = entityService.GetAllPaths(UmbracoObjectTypes.Document, startNodeIds).Select(x => x.Path).ToArray(); + return vals; + }, TimeSpan.FromMinutes(2), true); - private static void ToUserCache(IUser user, string cacheKey, T vals) - where T: class - { - if (!(user is User entityUser)) return; - - lock (entityUser.AdditionalDataLock) - { - entityUser.AdditionalData[cacheKey] = vals; - } + return result; } private static bool StartsWithPath(string test, string path) diff --git a/src/Umbraco.Core/Security/BackOfficeUserStore.cs b/src/Umbraco.Core/Security/BackOfficeUserStore.cs index 7df328b5b7..fe1673bca6 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserStore.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Threading.Tasks; using System.Web.Security; using Microsoft.AspNet.Identity; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Mapping; using Umbraco.Core.Models; @@ -38,20 +40,26 @@ namespace Umbraco.Core.Security private readonly IExternalLoginService _externalLoginService; private readonly IGlobalSettings _globalSettings; private readonly UmbracoMapper _mapper; + private readonly AppCaches _appCaches; private bool _disposed = false; + [Obsolete("Use the constructor specifying all dependencies")] public BackOfficeUserStore(IUserService userService, IMemberTypeService memberTypeService, IEntityService entityService, IExternalLoginService externalLoginService, IGlobalSettings globalSettings, MembershipProviderBase usersMembershipProvider, UmbracoMapper mapper) + : this(userService, memberTypeService, entityService, externalLoginService, globalSettings, usersMembershipProvider, mapper, Current.AppCaches) { } + + public BackOfficeUserStore(IUserService userService, IMemberTypeService memberTypeService, IEntityService entityService, IExternalLoginService externalLoginService, IGlobalSettings globalSettings, MembershipProviderBase usersMembershipProvider, UmbracoMapper mapper, AppCaches appCaches) { + if (userService == null) throw new ArgumentNullException("userService"); + if (usersMembershipProvider == null) throw new ArgumentNullException("usersMembershipProvider"); + if (externalLoginService == null) throw new ArgumentNullException("externalLoginService"); + _userService = userService; _memberTypeService = memberTypeService; _entityService = entityService; _externalLoginService = externalLoginService; - _globalSettings = globalSettings; - if (userService == null) throw new ArgumentNullException("userService"); - if (usersMembershipProvider == null) throw new ArgumentNullException("usersMembershipProvider"); - if (externalLoginService == null) throw new ArgumentNullException("externalLoginService"); + _globalSettings = globalSettings; _mapper = mapper; - + _appCaches = appCaches; _userService = userService; _externalLoginService = externalLoginService; @@ -775,8 +783,8 @@ namespace Umbraco.Core.Security } //we should re-set the calculated start nodes - identityUser.CalculatedMediaStartNodeIds = user.CalculateMediaStartNodeIds(_entityService); - identityUser.CalculatedContentStartNodeIds = user.CalculateContentStartNodeIds(_entityService); + identityUser.CalculatedMediaStartNodeIds = user.CalculateMediaStartNodeIds(_entityService, _appCaches); + identityUser.CalculatedContentStartNodeIds = user.CalculateContentStartNodeIds(_entityService, _appCaches); //reset all changes identityUser.ResetDirtyProperties(false); diff --git a/src/Umbraco.Core/Security/ContentPermissionsHelper.cs b/src/Umbraco.Core/Security/ContentPermissionsHelper.cs index 1a329fcdcb..8c3a138f6a 100644 --- a/src/Umbraco.Core/Security/ContentPermissionsHelper.cs +++ b/src/Umbraco.Core/Security/ContentPermissionsHelper.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -25,6 +26,7 @@ namespace Umbraco.Core.Security IUser user, IUserService userService, IEntityService entityService, + AppCaches appCaches, params char[] permissionsToCheck) { if (user == null) throw new ArgumentNullException("user"); @@ -33,7 +35,7 @@ namespace Umbraco.Core.Security if (content == null) return ContentAccess.NotFound; - var hasPathAccess = user.HasPathAccess(content, entityService); + var hasPathAccess = user.HasPathAccess(content, entityService, appCaches); if (hasPathAccess == false) return ContentAccess.Denied; @@ -52,6 +54,7 @@ namespace Umbraco.Core.Security IUser user, IUserService userService, IEntityService entityService, + AppCaches appCaches, params char[] permissionsToCheck) { if (user == null) throw new ArgumentNullException("user"); @@ -60,7 +63,7 @@ namespace Umbraco.Core.Security if (entity == null) return ContentAccess.NotFound; - var hasPathAccess = user.HasContentPathAccess(entity, entityService); + var hasPathAccess = user.HasContentPathAccess(entity, entityService, appCaches); if (hasPathAccess == false) return ContentAccess.Denied; @@ -89,6 +92,7 @@ namespace Umbraco.Core.Security IUser user, IUserService userService, IEntityService entityService, + AppCaches appCaches, out IUmbracoEntity entity, params char[] permissionsToCheck) { @@ -100,16 +104,16 @@ namespace Umbraco.Core.Security entity = null; if (nodeId == Constants.System.Root) - hasPathAccess = user.HasContentRootAccess(entityService); + hasPathAccess = user.HasContentRootAccess(entityService, appCaches); else if (nodeId == Constants.System.RecycleBinContent) - hasPathAccess = user.HasContentBinAccess(entityService); + hasPathAccess = user.HasContentBinAccess(entityService, appCaches); if (hasPathAccess.HasValue) return hasPathAccess.Value ? ContentAccess.Granted : ContentAccess.Denied; entity = entityService.Get(nodeId, UmbracoObjectTypes.Document); if (entity == null) return ContentAccess.NotFound; - hasPathAccess = user.HasContentPathAccess(entity, entityService); + hasPathAccess = user.HasContentPathAccess(entity, entityService, appCaches); if (hasPathAccess == false) return ContentAccess.Denied; @@ -140,6 +144,7 @@ namespace Umbraco.Core.Security IUserService userService, IContentService contentService, IEntityService entityService, + AppCaches appCaches, out IContent contentItem, params char[] permissionsToCheck) { @@ -152,16 +157,16 @@ namespace Umbraco.Core.Security contentItem = null; if (nodeId == Constants.System.Root) - hasPathAccess = user.HasContentRootAccess(entityService); + hasPathAccess = user.HasContentRootAccess(entityService, appCaches); else if (nodeId == Constants.System.RecycleBinContent) - hasPathAccess = user.HasContentBinAccess(entityService); + hasPathAccess = user.HasContentBinAccess(entityService, appCaches); if (hasPathAccess.HasValue) return hasPathAccess.Value ? ContentAccess.Granted : ContentAccess.Denied; contentItem = contentService.GetById(nodeId); if (contentItem == null) return ContentAccess.NotFound; - hasPathAccess = user.HasPathAccess(contentItem, entityService); + hasPathAccess = user.HasPathAccess(contentItem, entityService, appCaches); if (hasPathAccess == false) return ContentAccess.Denied; diff --git a/src/Umbraco.Tests/Models/UserExtensionsTests.cs b/src/Umbraco.Tests/Models/UserExtensionsTests.cs index bf76031b59..18ece0c841 100644 --- a/src/Umbraco.Tests/Models/UserExtensionsTests.cs +++ b/src/Umbraco.Tests/Models/UserExtensionsTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Moq; using NUnit.Framework; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -34,7 +35,7 @@ namespace Umbraco.Tests.Models .Setup(x => x.GetAllPaths(It.IsAny(), It.IsAny())) .Returns((type, ids) => new[] { new TreeEntityPath { Id = startNodeId, Path = startNodePath } }); - Assert.AreEqual(outcome, user.HasPathAccess(content, esmock.Object)); + Assert.AreEqual(outcome, user.HasPathAccess(content, esmock.Object, AppCaches.Disabled)); } [TestCase("", "1", "1")] // single user start, top level diff --git a/src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs b/src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs index f55a4e593b..26aea30c26 100644 --- a/src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs @@ -2,6 +2,7 @@ using System.Web.Http; using Moq; using NUnit.Framework; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -34,7 +35,7 @@ namespace Umbraco.Tests.Web.Controllers var userService = userServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, out var foundContent); + var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Granted, result); @@ -62,7 +63,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, out var foundContent, new[] { 'F' }); + var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent, new[] { 'F' }); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.NotFound, result); @@ -93,7 +94,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, out var foundContent, new[] { 'F' }); + var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent, new[] { 'F' }); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Denied, result); @@ -124,7 +125,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, out var foundContent, new[] { 'F' }); + var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent, new[] { 'F' }); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Denied, result); @@ -156,7 +157,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, out var foundContent, new[] { 'F' }); + var result = ContentPermissionsHelper.CheckPermissions(1234, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent, new[] { 'F' }); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Granted, result); @@ -178,7 +179,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, out var foundContent); + var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Granted, result); @@ -200,7 +201,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(-20, user, userService, contentService, entityService, out var foundContent); + var result = ContentPermissionsHelper.CheckPermissions(-20, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Granted, result); @@ -224,7 +225,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(-20, user, userService, contentService, entityService, out var foundContent); + var result = ContentPermissionsHelper.CheckPermissions(-20, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Denied, result); @@ -248,7 +249,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, out var foundContent); + var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Denied, result); @@ -278,7 +279,7 @@ namespace Umbraco.Tests.Web.Controllers //act - var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, out var foundContent, new[] { 'A' }); + var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent, new[] { 'A' }); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Granted, result); @@ -306,7 +307,7 @@ namespace Umbraco.Tests.Web.Controllers var contentService = contentServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, out var foundContent, new[] { 'B' }); + var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent, new[] { 'B' }); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Denied, result); @@ -336,7 +337,7 @@ namespace Umbraco.Tests.Web.Controllers var contentService = contentServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(-20, user, userService, contentService, entityService, out var foundContent, new[] { 'A' }); + var result = ContentPermissionsHelper.CheckPermissions(-20, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent, new[] { 'A' }); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Granted, result); @@ -364,7 +365,7 @@ namespace Umbraco.Tests.Web.Controllers var contentService = contentServiceMock.Object; //act - var result = ContentPermissionsHelper.CheckPermissions(-20, user, userService, contentService, entityService, out var foundContent, new[] { 'B' }); + var result = ContentPermissionsHelper.CheckPermissions(-20, user, userService, contentService, entityService, AppCaches.Disabled, out var foundContent, new[] { 'B' }); //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Denied, result); diff --git a/src/Umbraco.Tests/Web/Controllers/MediaControllerUnitTests.cs b/src/Umbraco.Tests/Web/Controllers/MediaControllerUnitTests.cs index f409d81a2d..c347d81288 100644 --- a/src/Umbraco.Tests/Web/Controllers/MediaControllerUnitTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/MediaControllerUnitTests.cs @@ -2,6 +2,7 @@ using System.Web.Http; using Moq; using NUnit.Framework; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -31,7 +32,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, 1234); + var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, AppCaches.Disabled, 1234); //assert Assert.IsTrue(result); @@ -54,7 +55,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act/assert - Assert.Throws(() => MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, 1234)); + Assert.Throws(() => MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, AppCaches.Disabled, 1234)); } [Test] @@ -77,7 +78,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, 1234); + var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, AppCaches.Disabled, 1234); //assert Assert.IsFalse(result); @@ -97,7 +98,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, -1); + var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, AppCaches.Disabled, -1); //assert Assert.IsTrue(result); @@ -119,7 +120,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, -1); + var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, AppCaches.Disabled, -1); //assert Assert.IsFalse(result); @@ -139,7 +140,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, -21); + var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, AppCaches.Disabled, -21); //assert Assert.IsTrue(result); @@ -161,7 +162,7 @@ namespace Umbraco.Tests.Web.Controllers var entityService = entityServiceMock.Object; //act - var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, -21); + var result = MediaController.CheckPermissions(new Dictionary(), user, mediaService, entityService, AppCaches.Disabled, -21); //assert Assert.IsFalse(result); diff --git a/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs b/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs index 04694b21ee..4478b59085 100644 --- a/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -32,7 +33,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new string[0]); @@ -54,7 +56,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new string[0]); @@ -79,7 +82,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] {"FunGroup"}); @@ -104,7 +108,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] { "test" }); @@ -141,7 +146,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); //adding 5555 which currentUser has access to since it's a child of 9876 ... adding is still ok even though currentUser doesn't have access to 1234 var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234, 5555 }, new int[0], new string[0]); @@ -179,7 +185,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); //removing 4567 start node even though currentUser doesn't have acces to it ... removing is ok var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234 }, new int[0], new string[0]); @@ -217,7 +224,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); //adding 1234 but currentUser doesn't have access to it ... nope var result = authHelper.IsAuthorized(currentUser, savingUser, new []{1234}, new int[0], new string[0]); @@ -255,7 +263,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); //adding 5555 which currentUser has access to since it's a child of 9876 ... ok var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 5555 }, new int[0], new string[0]); @@ -293,7 +302,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); //adding 1234 but currentUser doesn't have access to it ... nope var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] {1234}, new string[0]); @@ -331,7 +341,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); //adding 5555 which currentUser has access to since it's a child of 9876 ... ok var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 5555 }, new string[0]); @@ -369,7 +380,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); //adding 5555 which currentUser has access to since it's a child of 9876 ... adding is still ok even though currentUser doesn't have access to 1234 var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234, 5555 }, new string[0]); @@ -407,7 +419,8 @@ namespace Umbraco.Tests.Web.Controllers contentService.Object, mediaService.Object, userService.Object, - entityService.Object); + entityService.Object, + AppCaches.Disabled); //removing 4567 start node even though currentUser doesn't have acces to it ... removing is ok var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234 }, new string[0]); diff --git a/src/Umbraco.Web/Cache/UserCacheRefresher.cs b/src/Umbraco.Web/Cache/UserCacheRefresher.cs index 922a9df385..ce2cbbf754 100644 --- a/src/Umbraco.Web/Cache/UserCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserCacheRefresher.cs @@ -42,7 +42,14 @@ namespace Umbraco.Web.Cache { var userCache = AppCaches.IsolatedCaches.Get(); if (userCache) + { userCache.Result.Clear(RepositoryCacheKeys.GetKey(id)); + userCache.Result.ClearByKey(CacheKeys.UserContentStartNodePathsPrefix + id); + userCache.Result.ClearByKey(CacheKeys.UserMediaStartNodePathsPrefix + id); + userCache.Result.ClearByKey(CacheKeys.UserAllContentStartNodesPrefix + id); + userCache.Result.ClearByKey(CacheKeys.UserAllMediaStartNodesPrefix + id); + } + base.Remove(id); } diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 6f85a08751..7093edf23d 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1168,7 +1168,7 @@ namespace Umbraco.Web.Editors //if this item's path has already been denied or if the user doesn't have access to it, add to the deny list if (denied.Any(x => c.Path.StartsWith($"{x.Path},")) || (ContentPermissionsHelper.CheckPermissions(c, - Security.CurrentUser, Services.UserService, Services.EntityService, + Security.CurrentUser, Services.UserService, Services.EntityService, AppCaches, ActionPublish.ActionLetter) == ContentPermissionsHelper.ContentAccess.Denied)) { denied.Add(c); diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 65d9305906..456e0e20f2 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -670,9 +670,9 @@ namespace Umbraco.Web.Editors switch (type) { case UmbracoEntityTypes.Document: - return Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService); + return Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService, AppCaches); case UmbracoEntityTypes.Media: - return Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService); + return Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService, AppCaches); default: return Array.Empty(); } @@ -811,10 +811,10 @@ namespace Umbraco.Web.Editors switch (entityType) { case UmbracoEntityTypes.Document: - aids = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService); + aids = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService, AppCaches); break; case UmbracoEntityTypes.Media: - aids = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService); + aids = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService, AppCaches); break; } diff --git a/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs b/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs index fbce2d0414..c0e190989a 100644 --- a/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs @@ -7,6 +7,7 @@ using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Security; @@ -29,11 +30,12 @@ namespace Umbraco.Web.Editors.Filters private readonly IContentService _contentService; private readonly IUserService _userService; private readonly IEntityService _entityService; + private readonly AppCaches _appCaches; - public ContentSaveValidationAttribute(): this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.ContentService, Current.Services.UserService, Current.Services.EntityService) + public ContentSaveValidationAttribute(): this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.ContentService, Current.Services.UserService, Current.Services.EntityService, Current.AppCaches) { } - public ContentSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IContentService contentService, IUserService userService, IEntityService entityService) + public ContentSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IContentService contentService, IUserService userService, IEntityService entityService, AppCaches appCaches) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); @@ -41,6 +43,7 @@ namespace Umbraco.Web.Editors.Filters _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); + _appCaches = appCaches; } public override void OnActionExecuting(HttpActionContext actionContext) @@ -195,13 +198,13 @@ namespace Umbraco.Web.Editors.Filters accessResult = ContentPermissionsHelper.CheckPermissions( contentToCheck, webSecurity.CurrentUser, - _userService, _entityService, permissionToCheck.ToArray()); + _userService, _entityService, _appCaches, permissionToCheck.ToArray()); } else { accessResult = ContentPermissionsHelper.CheckPermissions( contentIdToCheck, webSecurity.CurrentUser, - _userService, _contentService, _entityService, + _userService, _contentService, _entityService, _appCaches, out contentToCheck, permissionToCheck.ToArray()); if (contentToCheck != null) diff --git a/src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs b/src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs index 449ef95675..af973d0662 100644 --- a/src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs @@ -4,6 +4,7 @@ using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; @@ -23,18 +24,20 @@ namespace Umbraco.Web.Editors.Filters private readonly ILocalizedTextService _textService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; + private readonly AppCaches _appCaches; - public MediaItemSaveValidationAttribute() : this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.MediaService, Current.Services.EntityService) + public MediaItemSaveValidationAttribute() : this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.MediaService, Current.Services.EntityService, Current.AppCaches) { } - public MediaItemSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IMediaService mediaService, IEntityService entityService) + public MediaItemSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IMediaService mediaService, IEntityService entityService, AppCaches appCaches) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); + _appCaches = appCaches; } public override void OnActionExecuting(HttpActionContext actionContext) @@ -91,7 +94,7 @@ namespace Umbraco.Web.Editors.Filters if (MediaController.CheckPermissions( actionContext.Request.Properties, _umbracoContextAccessor.UmbracoContext.Security.CurrentUser, - _mediaService, _entityService, + _mediaService, _entityService, _appCaches, contentIdToCheck, contentToCheck) == false) { actionContext.Response = actionContext.Request.CreateUserNoAccessResponse(); diff --git a/src/Umbraco.Web/Editors/Filters/UserGroupAuthorizationAttribute.cs b/src/Umbraco.Web/Editors/Filters/UserGroupAuthorizationAttribute.cs index e1d6626055..e94098db82 100644 --- a/src/Umbraco.Web/Editors/Filters/UserGroupAuthorizationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/UserGroupAuthorizationAttribute.cs @@ -54,7 +54,8 @@ namespace Umbraco.Web.Editors.Filters Current.Services.UserService, Current.Services.ContentService, Current.Services.MediaService, - Current.Services.EntityService); + Current.Services.EntityService, + Current.AppCaches); return authHelper.AuthorizeGroupAccess(currentUser, intIds); } } diff --git a/src/Umbraco.Web/Editors/Filters/UserGroupEditorAuthorizationHelper.cs b/src/Umbraco.Web/Editors/Filters/UserGroupEditorAuthorizationHelper.cs index 985c42bbbf..ea403758d0 100644 --- a/src/Umbraco.Web/Editors/Filters/UserGroupEditorAuthorizationHelper.cs +++ b/src/Umbraco.Web/Editors/Filters/UserGroupEditorAuthorizationHelper.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; @@ -13,13 +14,15 @@ namespace Umbraco.Web.Editors.Filters private readonly IContentService _contentService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; + private readonly AppCaches _appCaches; - public UserGroupEditorAuthorizationHelper(IUserService userService, IContentService contentService, IMediaService mediaService, IEntityService entityService) + public UserGroupEditorAuthorizationHelper(IUserService userService, IContentService contentService, IMediaService mediaService, IEntityService entityService, AppCaches appCaches) { _userService = userService; _contentService = contentService; _mediaService = mediaService; _entityService = entityService; + _appCaches = appCaches; } /// @@ -111,7 +114,7 @@ namespace Umbraco.Web.Editors.Filters var content = _contentService.GetById(proposedContentStartId.Value); if (content != null) { - if (currentUser.HasPathAccess(content, _entityService) == false) + if (currentUser.HasPathAccess(content, _entityService, _appCaches) == false) return Attempt.Fail("Current user doesn't have access to the content path " + content.Path); } } @@ -121,7 +124,7 @@ namespace Umbraco.Web.Editors.Filters var media = _mediaService.GetById(proposedMediaStartId.Value); if (media != null) { - if (currentUser.HasPathAccess(media, _entityService) == false) + if (currentUser.HasPathAccess(media, _entityService, _appCaches) == false) return Attempt.Fail("Current user doesn't have access to the media path " + media.Path); } } diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index dfe6939552..022512e2a4 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -239,7 +239,7 @@ namespace Umbraco.Web.Editors protected int[] UserStartNodes { - get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService)); } + get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService, AppCaches)); } } /// @@ -835,6 +835,7 @@ namespace Umbraco.Web.Editors Security.CurrentUser, Services.MediaService, Services.EntityService, + AppCaches, intParentId) == false) { throw new HttpResponseException(Request.CreateResponse( @@ -919,7 +920,7 @@ namespace Umbraco.Web.Editors /// The content to lookup, if the contentItem is not specified /// Specifies the already resolved content item to check against, setting this ignores the nodeId /// - internal static bool CheckPermissions(IDictionary storage, IUser user, IMediaService mediaService, IEntityService entityService, int nodeId, IMedia media = null) + internal static bool CheckPermissions(IDictionary storage, IUser user, IMediaService mediaService, IEntityService entityService, AppCaches appCaches, int nodeId, IMedia media = null) { if (storage == null) throw new ArgumentNullException("storage"); if (user == null) throw new ArgumentNullException("user"); @@ -940,10 +941,10 @@ namespace Umbraco.Web.Editors } var hasPathAccess = (nodeId == Constants.System.Root) - ? user.HasMediaRootAccess(entityService) + ? user.HasMediaRootAccess(entityService, appCaches) : (nodeId == Constants.System.RecycleBinMedia) - ? user.HasMediaBinAccess(entityService) - : user.HasPathAccess(media, entityService); + ? user.HasMediaBinAccess(entityService, appCaches) + : user.HasPathAccess(media, entityService, appCaches); return hasPathAccess; } diff --git a/src/Umbraco.Web/Editors/UserEditorAuthorizationHelper.cs b/src/Umbraco.Web/Editors/UserEditorAuthorizationHelper.cs index 320580aaf9..f666b6d5a3 100644 --- a/src/Umbraco.Web/Editors/UserEditorAuthorizationHelper.cs +++ b/src/Umbraco.Web/Editors/UserEditorAuthorizationHelper.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Security; @@ -14,13 +15,15 @@ namespace Umbraco.Web.Editors private readonly IMediaService _mediaService; private readonly IUserService _userService; private readonly IEntityService _entityService; + private readonly AppCaches _appCaches; - public UserEditorAuthorizationHelper(IContentService contentService, IMediaService mediaService, IUserService userService, IEntityService entityService) + public UserEditorAuthorizationHelper(IContentService contentService, IMediaService mediaService, IUserService userService, IEntityService entityService, AppCaches appCaches) { _contentService = contentService; _mediaService = mediaService; _userService = userService; _entityService = entityService; + _appCaches = appCaches; } /// @@ -114,7 +117,7 @@ namespace Umbraco.Web.Editors { if (contentId == Constants.System.Root) { - var hasAccess = ContentPermissionsHelper.HasPathAccess("-1", currentUser.CalculateContentStartNodeIds(_entityService), Constants.System.RecycleBinContent); + var hasAccess = ContentPermissionsHelper.HasPathAccess("-1", currentUser.CalculateContentStartNodeIds(_entityService, _appCaches), Constants.System.RecycleBinContent); if (hasAccess == false) return Attempt.Fail("The current user does not have access to the content root"); } @@ -122,7 +125,7 @@ namespace Umbraco.Web.Editors { var content = _contentService.GetById(contentId); if (content == null) continue; - var hasAccess = currentUser.HasPathAccess(content, _entityService); + var hasAccess = currentUser.HasPathAccess(content, _entityService, _appCaches); if (hasAccess == false) return Attempt.Fail("The current user does not have access to the content path " + content.Path); } @@ -135,7 +138,7 @@ namespace Umbraco.Web.Editors { if (mediaId == Constants.System.Root) { - var hasAccess = ContentPermissionsHelper.HasPathAccess("-1", currentUser.CalculateMediaStartNodeIds(_entityService), Constants.System.RecycleBinMedia); + var hasAccess = ContentPermissionsHelper.HasPathAccess("-1", currentUser.CalculateMediaStartNodeIds(_entityService, _appCaches), Constants.System.RecycleBinMedia); if (hasAccess == false) return Attempt.Fail("The current user does not have access to the media root"); } @@ -143,7 +146,7 @@ namespace Umbraco.Web.Editors { var media = _mediaService.GetById(mediaId); if (media == null) continue; - var hasAccess = currentUser.HasPathAccess(media, _entityService); + var hasAccess = currentUser.HasPathAccess(media, _entityService, _appCaches); if (hasAccess == false) return Attempt.Fail("The current user does not have access to the media path " + media.Path); } diff --git a/src/Umbraco.Web/Editors/UserGroupsController.cs b/src/Umbraco.Web/Editors/UserGroupsController.cs index b081ca6137..77f7a305af 100644 --- a/src/Umbraco.Web/Editors/UserGroupsController.cs +++ b/src/Umbraco.Web/Editors/UserGroupsController.cs @@ -28,7 +28,11 @@ namespace Umbraco.Web.Editors //authorize that the user has access to save this user group var authHelper = new UserGroupEditorAuthorizationHelper( - Services.UserService, Services.ContentService, Services.MediaService, Services.EntityService); + Services.UserService, + Services.ContentService, + Services.MediaService, + Services.EntityService, + AppCaches); var isAuthorized = authHelper.AuthorizeGroupAccess(Security.CurrentUser, userGroupSave.Alias); if (isAuthorized == false) diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index b022e6f27a..21a32ef12f 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -304,7 +304,7 @@ namespace Umbraco.Web.Editors CheckUniqueEmail(userSave.Email, null); //Perform authorization here to see if the current user can actually save this user with the info being requested - var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService); + var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService, AppCaches); var canSaveUser = authHelper.IsAuthorized(Security.CurrentUser, null, null, null, userSave.UserGroups); if (canSaveUser == false) { @@ -398,7 +398,7 @@ namespace Umbraco.Web.Editors } //Perform authorization here to see if the current user can actually save this user with the info being requested - var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService); + var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService, AppCaches); var canSaveUser = authHelper.IsAuthorized(Security.CurrentUser, user, null, null, userSave.UserGroups); if (canSaveUser == false) { @@ -573,7 +573,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); //Perform authorization here to see if the current user can actually save this user with the info being requested - var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService); + var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService, AppCaches); var canSaveUser = authHelper.IsAuthorized(Security.CurrentUser, found, userSave.StartContentIds, userSave.StartMediaIds, userSave.UserGroups); if (canSaveUser == false) { diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/ContentMapDefinition.cs index 983172f8e1..ec3367d4d3 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentMapDefinition.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; @@ -29,14 +31,25 @@ namespace Umbraco.Web.Models.Mapping private readonly ILogger _logger; private readonly IUserService _userService; private readonly IEntityService _entityService; + private readonly AppCaches _appCaches; private readonly TabsAndPropertiesMapper _tabsAndPropertiesMapper; private readonly ContentSavedStateMapper _stateMapper; private readonly ContentBasicSavedStateMapper _basicStateMapper; private readonly ContentVariantMapper _contentVariantMapper; - public ContentMapDefinition(CommonMapper commonMapper, ILocalizedTextService localizedTextService, IContentService contentService, IContentTypeService contentTypeService, - IFileService fileService, IUmbracoContextAccessor umbracoContextAccessor, IPublishedRouter publishedRouter, ILocalizationService localizationService, ILogger logger, - IUserService userService, IEntityService entityService) + public ContentMapDefinition( + CommonMapper commonMapper, + ILocalizedTextService localizedTextService, + IContentService contentService, + IContentTypeService contentTypeService, + IFileService fileService, + IUmbracoContextAccessor umbracoContextAccessor, + IPublishedRouter publishedRouter, + ILocalizationService localizationService, + ILogger logger, + IUserService userService, + IEntityService entityService, + AppCaches appCaches) { _commonMapper = commonMapper; _localizedTextService = localizedTextService; @@ -49,6 +62,7 @@ namespace Umbraco.Web.Models.Mapping _logger = logger; _userService = userService; _entityService = entityService; + _appCaches = appCaches; _tabsAndPropertiesMapper = new TabsAndPropertiesMapper(localizedTextService); _stateMapper = new ContentSavedStateMapper(); _basicStateMapper = new ContentBasicSavedStateMapper(); @@ -238,7 +252,7 @@ namespace Umbraco.Web.Models.Mapping // false here. if (context.HasItems && context.Items.TryGetValue("CurrentUser", out var usr) && usr is IUser currentUser) { - userStartNodes = currentUser.CalculateContentStartNodeIds(_entityService); + userStartNodes = currentUser.CalculateContentStartNodeIds(_entityService, _appCaches); if (!userStartNodes.Contains(Constants.System.Root)) { // return false if this is the user's actual start node, the node will be rendered in the tree diff --git a/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs index aa158799cb..6c58309f57 100644 --- a/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs @@ -273,8 +273,8 @@ namespace Umbraco.Web.Models.Mapping { target.AvailableCultures = _textService.GetSupportedCultures().ToDictionary(x => x.Name, x => x.DisplayName); target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache); - target.CalculatedStartContentIds = GetStartNodes(source.CalculateContentStartNodeIds(_entityService), UmbracoObjectTypes.Document, "content/contentRoot", context); - target.CalculatedStartMediaIds = GetStartNodes(source.CalculateMediaStartNodeIds(_entityService), UmbracoObjectTypes.Media, "media/mediaRoot", context); + target.CalculatedStartContentIds = GetStartNodes(source.CalculateContentStartNodeIds(_entityService, _appCaches), UmbracoObjectTypes.Document, "content/contentRoot", context); + target.CalculatedStartMediaIds = GetStartNodes(source.CalculateMediaStartNodeIds(_entityService, _appCaches), UmbracoObjectTypes.Media, "media/mediaRoot", context); target.CreateDate = source.CreateDate; target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString(); target.Email = source.Email; @@ -327,8 +327,8 @@ namespace Umbraco.Web.Models.Mapping target.Email = source.Email; target.EmailHash = source.Email.ToLowerInvariant().Trim().GenerateHash(); target.Name = source.Name; - target.StartContentIds = source.CalculateContentStartNodeIds(_entityService); - target.StartMediaIds = source.CalculateMediaStartNodeIds(_entityService); + target.StartContentIds = source.CalculateContentStartNodeIds(_entityService, _appCaches); + target.StartMediaIds = source.CalculateMediaStartNodeIds(_entityService, _appCaches); target.UserId = source.Id; //we need to map the legacy UserType diff --git a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs index a22e2a6f6a..6d777287d6 100644 --- a/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs +++ b/src/Umbraco.Web/Search/UmbracoTreeSearcher.cs @@ -5,6 +5,8 @@ using System.Text; using System.Text.RegularExpressions; using Examine; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -30,14 +32,29 @@ namespace Umbraco.Web.Search private readonly UmbracoMapper _mapper; private readonly ISqlContext _sqlContext; private readonly IUmbracoTreeSearcherFields _umbracoTreeSearcherFields; + private readonly AppCaches _appCaches; - - public UmbracoTreeSearcher(IExamineManager examineManager, + [Obsolete("Use constructor specifying all dependencies instead")] + public UmbracoTreeSearcher( + IExamineManager examineManager, UmbracoContext umbracoContext, ILocalizationService languageService, IEntityService entityService, UmbracoMapper mapper, - ISqlContext sqlContext,IUmbracoTreeSearcherFields umbracoTreeSearcherFields) + ISqlContext sqlContext, + IUmbracoTreeSearcherFields umbracoTreeSearcherFields) + : this(examineManager, umbracoContext, languageService, entityService, mapper, sqlContext, umbracoTreeSearcherFields, Current.AppCaches) + { } + + public UmbracoTreeSearcher( + IExamineManager examineManager, + UmbracoContext umbracoContext, + ILocalizationService languageService, + IEntityService entityService, + UmbracoMapper mapper, + ISqlContext sqlContext, + IUmbracoTreeSearcherFields umbracoTreeSearcherFields, + AppCaches appCaches) { _examineManager = examineManager ?? throw new ArgumentNullException(nameof(examineManager)); _umbracoContext = umbracoContext; @@ -46,6 +63,7 @@ namespace Umbraco.Web.Search _mapper = mapper; _sqlContext = sqlContext; _umbracoTreeSearcherFields = umbracoTreeSearcherFields; + _appCaches = appCaches; } /// @@ -112,13 +130,13 @@ namespace Umbraco.Web.Search case UmbracoEntityTypes.Media: type = "media"; fields.AddRange(_umbracoTreeSearcherFields.GetBackOfficeMediaFields()); - var allMediaStartNodes = _umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService); + var allMediaStartNodes = _umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService, _appCaches); AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, ignoreUserStartNodes, _entityService); break; case UmbracoEntityTypes.Document: type = "content"; fields.AddRange(_umbracoTreeSearcherFields.GetBackOfficeDocumentFields()); - var allContentStartNodes = _umbracoContext.Security.CurrentUser.CalculateContentStartNodeIds(_entityService); + var allContentStartNodes = _umbracoContext.Security.CurrentUser.CalculateContentStartNodeIds(_entityService, _appCaches); AppendPath(sb, UmbracoObjectTypes.Document, allContentStartNodes, searchFrom, ignoreUserStartNodes, _entityService); break; default: @@ -462,11 +480,13 @@ namespace Umbraco.Web.Search var defaultLang = _languageService.GetDefaultLanguageIsoCode(); foreach (var result in results) { - var entity = _mapper.Map(result, context => { - if(culture != null) { - context.SetCulture(culture); - } + var entity = _mapper.Map(result, context => + { + if (culture != null) + { + context.SetCulture(culture); } + } ); var intId = entity.Id.TryConvertTo(); diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index 663af43643..4bf5be4008 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -47,7 +47,7 @@ namespace Umbraco.Web.Trees private int[] _userStartNodes; protected override int[] UserStartNodes - => _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService)); + => _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService, AppCaches)); public ContentTreeController(UmbracoTreeSearcher treeSearcher, ActionCollection actions, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { @@ -165,7 +165,7 @@ namespace Umbraco.Web.Trees } //if the user has no path access for this node, all they can do is refresh - if (!Security.CurrentUser.HasContentPathAccess(item, Services.EntityService)) + if (!Security.CurrentUser.HasContentPathAccess(item, Services.EntityService, AppCaches)) { var menu = new MenuItemCollection(); menu.Items.Add(new RefreshNode(Services.TextService, true)); diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index 95de72b7bf..afb38dea07 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -126,12 +126,12 @@ namespace Umbraco.Web.Trees switch (RecycleBinId) { case Constants.System.RecycleBinMedia: - startNodeIds = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService); - startNodePaths = Security.CurrentUser.GetMediaStartNodePaths(Services.EntityService); + startNodeIds = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService, AppCaches); + startNodePaths = Security.CurrentUser.GetMediaStartNodePaths(Services.EntityService, AppCaches); break; case Constants.System.RecycleBinContent: - startNodeIds = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService); - startNodePaths = Security.CurrentUser.GetContentStartNodePaths(Services.EntityService); + startNodeIds = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService, AppCaches); + startNodePaths = Security.CurrentUser.GetContentStartNodePaths(Services.EntityService, AppCaches); break; default: throw new NotSupportedException("Path access is only determined on content or media"); @@ -291,8 +291,8 @@ namespace Umbraco.Web.Trees { if (entity == null) return false; return RecycleBinId == Constants.System.RecycleBinContent - ? Security.CurrentUser.HasContentPathAccess(entity, Services.EntityService) - : Security.CurrentUser.HasMediaPathAccess(entity, Services.EntityService); + ? Security.CurrentUser.HasContentPathAccess(entity, Services.EntityService, AppCaches) + : Security.CurrentUser.HasMediaPathAccess(entity, Services.EntityService, AppCaches); } /// diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs index df44a809c9..2ad3c2af0a 100644 --- a/src/Umbraco.Web/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web/Trees/MediaTreeController.cs @@ -50,7 +50,7 @@ namespace Umbraco.Web.Trees private int[] _userStartNodes; protected override int[] UserStartNodes - => _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService)); + => _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService, AppCaches)); /// /// Creates a tree node for a content item based on an UmbracoEntity @@ -117,7 +117,7 @@ namespace Umbraco.Web.Trees } //if the user has no path access for this node, all they can do is refresh - if (!Security.CurrentUser.HasMediaPathAccess(item, Services.EntityService)) + if (!Security.CurrentUser.HasMediaPathAccess(item, Services.EntityService, AppCaches)) { menu.Items.Add(new RefreshNode(Services.TextService, true)); return menu; diff --git a/src/Umbraco.Web/WebApi/Filters/AdminUsersAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/Filters/AdminUsersAuthorizeAttribute.cs index 96226622b0..3494a5c0c7 100644 --- a/src/Umbraco.Web/WebApi/Filters/AdminUsersAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/AdminUsersAuthorizeAttribute.cs @@ -50,7 +50,7 @@ namespace Umbraco.Web.WebApi.Filters if (userIds.Length == 0) return base.IsAuthorized(actionContext); var users = Current.Services.UserService.GetUsersById(userIds); - var authHelper = new UserEditorAuthorizationHelper(Current.Services.ContentService, Current.Services.MediaService, Current.Services.UserService, Current.Services.EntityService); + var authHelper = new UserEditorAuthorizationHelper(Current.Services.ContentService, Current.Services.MediaService, Current.Services.UserService, Current.Services.EntityService, Current.AppCaches); return users.All(user => authHelper.IsAuthorized(Current.UmbracoContext.Security.CurrentUser, user, null, null, null) != false); } } diff --git a/src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs b/src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs index 2a57ec10b2..3bbee7ca41 100644 --- a/src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs @@ -85,12 +85,12 @@ namespace Umbraco.Web.WebApi.Filters () => user.Groups.Select(x => x.Alias).UnsortedSequenceEqual(identity.Roles) == false, () => { - var startContentIds = UserExtensions.CalculateContentStartNodeIds(user, Current.Services.EntityService); + var startContentIds = UserExtensions.CalculateContentStartNodeIds(user, Current.Services.EntityService, Current.AppCaches); return startContentIds.UnsortedSequenceEqual(identity.StartContentNodes) == false; }, () => { - var startMediaIds = UserExtensions.CalculateMediaStartNodeIds(user, Current.Services.EntityService); + var startMediaIds = UserExtensions.CalculateMediaStartNodeIds(user, Current.Services.EntityService, Current.AppCaches); return startMediaIds.UnsortedSequenceEqual(identity.StartMediaNodes) == false; } }; diff --git a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs index 28f09b46b7..fcf8cf1dd6 100644 --- a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs @@ -115,11 +115,13 @@ namespace Umbraco.Web.WebApi.Filters nodeId = _nodeId.Value; } - var permissionResult = ContentPermissionsHelper.CheckPermissions(nodeId, + var permissionResult = ContentPermissionsHelper.CheckPermissions( + nodeId, Current.UmbracoContext.Security.CurrentUser, Current.Services.UserService, Current.Services.ContentService, Current.Services.EntityService, + Current.AppCaches, out var contentItem, _permissionToCheck.HasValue ? new[] { _permissionToCheck.Value } : null); diff --git a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForMediaAttribute.cs b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForMediaAttribute.cs index 60e2889fd5..ef99aa4778 100644 --- a/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForMediaAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForMediaAttribute.cs @@ -124,6 +124,7 @@ namespace Umbraco.Web.WebApi.Filters Current.UmbracoContext.Security.CurrentUser, Current.Services.MediaService, Current.Services.EntityService, + Current.AppCaches, nodeId)) { base.OnActionExecuting(actionContext); diff --git a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs index 31e0b22ce1..23512aa144 100644 --- a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs @@ -9,7 +9,7 @@ using Umbraco.Core; using Umbraco.Web.Composing; using Umbraco.Core.Models; using Umbraco.Web.Actions; - +using Umbraco.Core.Cache; namespace Umbraco.Web.WebApi.Filters { @@ -21,52 +21,48 @@ namespace Umbraco.Web.WebApi.Filters { private readonly IUserService _userService; private readonly IEntityService _entityService; + private readonly AppCaches _appCaches; private readonly char _permissionToCheck; public FilterAllowedOutgoingContentAttribute(Type outgoingType) - : this(outgoingType, Current.Services.UserService, Current.Services.EntityService) + : this(outgoingType, ActionBrowse.ActionLetter, string.Empty, Current.Services.UserService, Current.Services.EntityService, Current.AppCaches) { - _permissionToCheck = ActionBrowse.ActionLetter; } public FilterAllowedOutgoingContentAttribute(Type outgoingType, char permissionToCheck) - : this(outgoingType, Current.Services.UserService, Current.Services.EntityService) + : this(outgoingType, permissionToCheck, string.Empty, Current.Services.UserService, Current.Services.EntityService, Current.AppCaches) { - _permissionToCheck = permissionToCheck; } public FilterAllowedOutgoingContentAttribute(Type outgoingType, string propertyName) - : this(outgoingType, propertyName, Current.Services.UserService, Current.Services.EntityService) + : this(outgoingType, ActionBrowse.ActionLetter, propertyName, Current.Services.UserService, Current.Services.EntityService, Current.AppCaches) { - _permissionToCheck = ActionBrowse.ActionLetter; } public FilterAllowedOutgoingContentAttribute(Type outgoingType, IUserService userService, IEntityService entityService) - : base(outgoingType) + : this(outgoingType, ActionBrowse.ActionLetter, string.Empty, userService, entityService, Current.AppCaches) { - _userService = userService ?? throw new ArgumentNullException(nameof(userService)); - _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); - _permissionToCheck = ActionBrowse.ActionLetter; } public FilterAllowedOutgoingContentAttribute(Type outgoingType, char permissionToCheck, IUserService userService, IEntityService entityService) - : base(outgoingType) + : this(outgoingType, permissionToCheck, string.Empty, userService, entityService, Current.AppCaches) { - _userService = userService ?? throw new ArgumentNullException(nameof(userService)); - _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); - _userService = userService; - _entityService = entityService; - _permissionToCheck = permissionToCheck; } public FilterAllowedOutgoingContentAttribute(Type outgoingType, string propertyName, IUserService userService, IEntityService entityService) + : this(outgoingType, ActionBrowse.ActionLetter, propertyName, userService, entityService, Current.AppCaches) + { + } + + private FilterAllowedOutgoingContentAttribute(Type outgoingType, char permissionToCheck, string propertyName, IUserService userService, IEntityService entityService, AppCaches appCaches) : base(outgoingType, propertyName) { _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); + _appCaches = appCaches; _userService = userService; _entityService = entityService; - _permissionToCheck = ActionBrowse.ActionLetter; + _permissionToCheck = permissionToCheck; } protected override void FilterItems(IUser user, IList items) @@ -78,7 +74,7 @@ namespace Umbraco.Web.WebApi.Filters protected override int[] GetUserStartNodes(IUser user) { - return user.CalculateContentStartNodeIds(_entityService); + return user.CalculateContentStartNodeIds(_entityService, _appCaches); } protected override int RecycleBinId diff --git a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs index 21dc60e6cc..5e308bd3c1 100644 --- a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs @@ -39,7 +39,7 @@ namespace Umbraco.Web.WebApi.Filters protected virtual int[] GetUserStartNodes(IUser user) { - return user.CalculateMediaStartNodeIds(Current.Services.EntityService); + return user.CalculateMediaStartNodeIds(Current.Services.EntityService, Current.AppCaches); } protected virtual int RecycleBinId => Constants.System.RecycleBinMedia;