Merge branch 'user-group-permissions' of https://github.com/umbraco/Umbraco-CMS into user-group-permissions

# Conflicts:
#	src/Umbraco.Web/Models/Mapping/UserModelMapper.cs
This commit is contained in:
Shannon
2017-07-19 19:26:26 +10:00
23 changed files with 474 additions and 212 deletions
+1 -1
View File
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.7.0")]
[assembly: AssemblyInformationalVersion("7.7.0-alpha001")]
[assembly: AssemblyInformationalVersion("7.7.0-alpha002")]
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return "alpha001"; } }
public static string CurrentComment { get { return "alpha002"; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
+6 -6
View File
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Models
private DateTime? _expireDate;
private int _writer;
private string _nodeName;//NOTE Once localization is introduced this will be the non-localized Node Name.
private bool _permissionsChanged;
/// <summary>
/// Constructor for creating a Content object
/// </summary>
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Models
/// <param name="contentType">ContentType for the current Content object</param>
public Content(string name, IContent parent, IContentType contentType)
: this(name, parent, contentType, new PropertyCollection())
{
{
}
/// <summary>
@@ -68,7 +68,7 @@ namespace Umbraco.Core.Models
/// <param name="parentId">Id of the Parent content</param>
/// <param name="contentType">ContentType for the current Content object</param>
/// <param name="properties">Collection of properties</param>
public Content(string name, int parentId, IContentType contentType, PropertyCollection properties)
public Content(string name, int parentId, IContentType contentType, PropertyCollection properties)
: base(name, parentId, contentType, properties)
{
Mandate.ParameterNotNull(contentType, "contentType");
@@ -94,7 +94,7 @@ namespace Umbraco.Core.Models
/// This is used to override the default one from the ContentType.
/// </summary>
/// <remarks>
/// If no template is explicitly set on the Content object,
/// If no template is explicitly set on the Content object,
/// the Default template from the ContentType will be returned.
/// </remarks>
[DataMember]
@@ -195,7 +195,7 @@ namespace Umbraco.Core.Models
get { return _nodeName; }
set { SetPropertyValueAndDetectChanges(value, ref _nodeName, Ps.Value.NodeNameSelector); }
}
/// <summary>
/// Gets the ContentType used by this content object
@@ -283,7 +283,7 @@ namespace Umbraco.Core.Models
ChangePublishedState(PublishedState.Unpublished);
}
}
/// <summary>
/// Method to call when Entity is being updated
/// </summary>
@@ -46,15 +46,5 @@ namespace Umbraco.Core.Models.Membership
/// Will hold the media file system relative path of the users custom avatar if they uploaded one
/// </summary>
string Avatar { get; set; }
/// <summary>
/// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups
/// </summary>
int[] AllStartContentIds { get; }
/// <summary>
/// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups
/// </summary>
int[] AllStartMediaIds { get; }
}
}
+25 -26
View File
@@ -115,10 +115,8 @@ namespace Umbraco.Core.Models.Membership
private DateTime _lastPasswordChangedDate;
private DateTime _lastLoginDate;
private DateTime _lastLockoutDate;
private bool _defaultToLiveEditing;
private int[] _allStartContentIds;
private int[] _allStartMediaIds;
private IDictionary<string, object> _additionalData;
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
@@ -300,25 +298,7 @@ namespace Umbraco.Core.Models.Membership
{
get { return _avatar; }
set { SetPropertyValueAndDetectChanges(value, ref _avatar, Ps.Value.AvatarSelector); }
}
/// <summary>
/// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups
/// </summary>
[IgnoreDataMember]
public int[] AllStartContentIds
{
get { return _allStartContentIds ?? (_allStartContentIds = StartContentIds.Concat(Groups.Where(x => x.StartContentId.HasValue).Select(x => x.StartContentId.Value)).Distinct().ToArray()); }
}
/// <summary>
/// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups
/// </summary>
[IgnoreDataMember]
public int[] AllStartMediaIds
{
get { return _allStartMediaIds ?? (_allStartMediaIds = StartMediaIds.Concat(Groups.Where(x => x.StartMediaId.HasValue).Select(x => x.StartMediaId.Value)).Distinct().ToArray()); }
}
}
/// <summary>
/// Gets or sets the session timeout.
@@ -417,18 +397,37 @@ namespace Umbraco.Core.Models.Membership
_allowedSections = null;
OnPropertyChanged(Ps.Value.UserGroupsSelector);
}
}
}
#endregion
/// <summary>
/// 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
/// </summary>
[IgnoreDataMember]
[DoNotClone]
internal IDictionary<string, object> AdditionalData
{
get { return _additionalData ?? (_additionalData = new Dictionary<string, object>()); }
}
public override object DeepClone()
{
var clone = (User)base.DeepClone();
//turn off change tracking
clone.DisableChangeTracking();
//manually clone the start node props
clone._startContentIds = _startContentIds.ToArray();
clone._startMediaIds = _startMediaIds.ToArray();
//turn off change tracking
clone.DisableChangeTracking();
//This ensures that any value in the dictionary that is deep cloneable is cloned too
foreach (var key in clone.AdditionalData.Keys.ToArray())
{
var deepCloneable = clone.AdditionalData[key] as IDeepCloneable;
if (deepCloneable != null)
{
clone.AdditionalData[key] = deepCloneable.DeepClone();
}
}
//need to create new collections otherwise they'll get copied by ref
clone._userGroups = new HashSet<IReadOnlyUserGroup>(_userGroups);
clone._allowedSections = _allowedSections != null ? new List<string>(_allowedSections) : null;
+135 -28
View File
@@ -81,7 +81,7 @@ namespace Umbraco.Core.Models
/// </summary>
/// <param name="user"></param>
/// <param name="textService"></param>
/// <returns></returns>
/// <returns></returns>
public static CultureInfo GetUserCulture(this IUser user, ILocalizedTextService textService)
{
if (user == null) throw new ArgumentNullException("user");
@@ -94,7 +94,7 @@ namespace Umbraco.Core.Models
try
{
var culture = CultureInfo.GetCultureInfo(userLanguage.Replace("_", "-"));
//TODO: This is a hack because we store the user language as 2 chars instead of the full culture
//TODO: This is a hack because we store the user language as 2 chars instead of the full culture
// which is actually stored in the language files (which are also named with 2 chars!) so we need to attempt
// to convert to a supported full culture
var result = textService.ConvertToSupportedCultureWithRegionCode(culture);
@@ -107,19 +107,36 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Checks if the user has access to the content item based on their start noe
/// </summary>
/// <param name="user"></param>
/// <param name="content"></param>
/// <returns></returns>
internal static bool HasPathAccess(this IUser user, IContent content)
internal static bool HasContentRootAccess(this IUser user, IEntityService entityService)
{
if (user == null) throw new ArgumentNullException("user");
if (content == null) throw new ArgumentNullException("content");
return HasPathAccess(content.Path, user.AllStartContentIds, Constants.System.RecycleBinContent);
return HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasContentBinAccess(this IUser user, IEntityService entityService)
{
return HasPathAccess(Constants.System.RecycleBinContent.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasMediaRootAccess(this IUser user, IEntityService entityService)
{
return HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasMediaBinAccess(this IUser user, IEntityService entityService)
{
return HasPathAccess(Constants.System.RecycleBinMedia.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasPathAccess(this IUser user, IContent content, IEntityService entityService)
{
return HasPathAccess(content.Path, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasPathAccess(this IUser user, IMedia media, IEntityService entityService)
{
return HasPathAccess(media.Path, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasPathAccess(string path, int[] startNodeIds, int recycleBinId)
{
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Value cannot be null or whitespace.", "path");
@@ -136,11 +153,11 @@ namespace Umbraco.Core.Models
if (formattedPath.Contains(formattedRecycleBinId))
{
return false;
}
}
//check for normal paths
foreach (var startNodeId in startNodeIds)
{
{
var formattedStartNodeId = "," + startNodeId.ToInvariantString() + ",";
var hasAccess = formattedPath.Contains(formattedStartNodeId);
@@ -151,19 +168,6 @@ namespace Umbraco.Core.Models
return false;
}
/// <summary>
/// Checks if the user has access to the media item based on their start noe
/// </summary>
/// <param name="user"></param>
/// <param name="media"></param>
/// <returns></returns>
internal static bool HasPathAccess(this IUser user, IMedia media)
{
if (user == null) throw new ArgumentNullException("user");
if (media == null) throw new ArgumentNullException("media");
return HasPathAccess(media.Path, user.AllStartMediaIds, Constants.System.RecycleBinMedia);
}
/// <summary>
/// Determines whether this user is an admin.
/// </summary>
@@ -176,5 +180,108 @@ namespace Umbraco.Core.Models
if (user == null) throw new ArgumentNullException("user");
return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.AdminGroupAlias);
}
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;
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;
}
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;
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;
}
private static int[] FromUserCache(IUser user, string cacheKey)
{
var entityUser = user as User;
if (entityUser != null)
{
object allContentStartNodes;
if (entityUser.AdditionalData.TryGetValue(cacheKey, out allContentStartNodes))
{
var asArray = allContentStartNodes as int[];
if (asArray != null) return asArray;
}
}
return null;
}
private static void ToUserCache(IUser user, string cacheKey, int[] vals)
{
var entityUser = user as User;
if (entityUser != null)
{
entityUser.AdditionalData[cacheKey] = vals;
}
}
private static bool StartsWithPath(string test, string path)
{
return test.StartsWith(path) && test.Length > path.Length && test[path.Length] == ',';
}
//TODO: Unit test this
internal static int[] CombineStartNodes(UmbracoObjectTypes objectType, int[] groupSn, int[] userSn, IEntityService entityService)
{
// assume groupSn and userSn each don't contain duplicates
var asn = groupSn.Concat(userSn).Distinct().ToArray();
//TODO: Change this to a more optimal lookup just to retrieve paths
var paths = entityService.GetAll(objectType, asn).ToDictionary(x => x.Id, x => x.Path);
paths[-1] = "-1"; // entityService does not get that one
var lsn = new List<int>();
foreach (var sn in groupSn)
{
string snp;
if (paths.TryGetValue(sn, out snp) == false) continue; // ignore
if (lsn.Any(x => StartsWithPath(snp, paths[x]))) continue; // skip if something above this sn
lsn.RemoveAll(x => StartsWithPath(paths[x], snp)); // remove anything below this sn
lsn.Add(sn);
}
var usn = new List<int>();
foreach (var sn in userSn)
{
if (groupSn.Contains(sn)) continue;
string snp;
if (paths.TryGetValue(sn, out snp) == false) continue; // ignore
if (usn.Any(x => StartsWithPath(paths[x], snp))) continue; // skip if something below this sn
usn.RemoveAll(x => StartsWithPath(snp, paths[x])); // remove anything above this sn
usn.Add(sn);
}
foreach (var sn in usn)
{
var snp = paths[sn]; // has to be here now
lsn.RemoveAll(x => StartsWithPath(snp, paths[x]) || StartsWithPath(paths[x], snp)); // remove anything above or below this sn
lsn.Add(sn);
}
return lsn.ToArray();
}
}
}
+21 -12
View File
@@ -1,29 +1,38 @@
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class UserExtensionsTests
{
[TestCase(2, "-1,1,2,3,4,5", true)]
[TestCase(6, "-1,1,2,3,4,5", false)]
[TestCase(-1, "-1,1,2,3,4,5", true)]
[TestCase(5, "-1,1,2,3,4,5", true)]
[TestCase(-1, "-1,-20,1,2,3,4,5", true)]
[TestCase(1, "-1,-20,1,2,3,4,5", false)]
public void Determines_Path_Based_Access_To_Content(int userId, string contentPath, bool outcome)
[TestCase(2, "-1,1,2", "-1,1,2,3,4,5", true)]
[TestCase(6, "-1,1,2,3,4,5,6", "-1,1,2,3,4,5", false)]
[TestCase(-1, "-1", "-1,1,2,3,4,5", true)]
[TestCase(5, "-1,1,2,3,4,5", "-1,1,2,3,4,5", true)]
[TestCase(-1, "-1", "-1,-20,1,2,3,4,5", true)]
[TestCase(1, "-1,-20,1", "-1,-20,1,2,3,4,5", false)]
public void Determines_Path_Based_Access_To_Content(int startNodeId, string startNodePath, string contentPath, bool outcome)
{
var userMock = new Mock<IUser>();
userMock.Setup(u => u.AllStartContentIds).Returns(new[]{ userId });
userMock.Setup(u => u.StartContentIds).Returns(new[]{ startNodeId });
var user = userMock.Object;
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns(contentPath);
var content = contentMock.Object;
var content = Mock.Of<IContent>(c => c.Path == contentPath && c.Id == 5);
Assert.AreEqual(outcome, user.HasPathAccess(content));
var entityServiceMock = new Mock<IEntityService>();
entityServiceMock.Setup(x => x.GetAll(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[]
{
Mock.Of<IUmbracoEntity>(entity => entity.Id == startNodeId && entity.Path == startNodePath)
});
var entityService = entityServiceMock.Object;
Assert.AreEqual(outcome, user.HasPathAccess(content, entityService));
}
}
}
@@ -3,6 +3,7 @@ using System.Web.Http;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.Editors;
@@ -18,7 +19,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
@@ -26,9 +26,13 @@ namespace Umbraco.Tests.Web.Controllers
var contentServiceMock = new Mock<IContentService>();
contentServiceMock.Setup(x => x.GetById(1234)).Returns(content);
var contentService = contentServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, null, contentService, 1234);
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, 1234);
//assert
Assert.IsTrue(result);
@@ -40,7 +44,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
@@ -53,9 +56,11 @@ namespace Umbraco.Tests.Web.Controllers
var permissionSet = new EntityPermissionSet(1234, permissions);
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet);
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act/assert
Assert.Throws<HttpResponseException>(() => ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, 1234, new[] { 'F' }));
Assert.Throws<HttpResponseException>(() => ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, 1234, new[] { 'F' }));
}
[Test]
@@ -64,7 +69,7 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartContentIds).Returns(new[]{ 9876 });
userMock.Setup(u => u.StartContentIds).Returns(new[]{ 9876 });
var user = userMock.Object;
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
@@ -77,9 +82,13 @@ namespace Umbraco.Tests.Web.Controllers
var permissionSet = new EntityPermissionSet(1234, permissions);
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234")).Returns(permissionSet);
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
entityServiceMock.Setup(x => x.GetAll(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<IUmbracoEntity>(entity => entity.Id == 9876 && entity.Path == "-1,9876") });
var entityService = entityServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, 1234, new[] { 'F'});
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, 1234, new[] { 'F'});
//assert
Assert.IsFalse(result);
@@ -91,7 +100,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
@@ -107,9 +115,11 @@ namespace Umbraco.Tests.Web.Controllers
var permissionSet = new EntityPermissionSet(1234, permissions);
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet);
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, 1234, new[] { 'F'});
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, 1234, new[] { 'F'});
//assert
Assert.IsFalse(result);
@@ -121,7 +131,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
@@ -129,17 +138,19 @@ namespace Umbraco.Tests.Web.Controllers
var contentServiceMock = new Mock<IContentService>();
contentServiceMock.Setup(x => x.GetById(1234)).Returns(content);
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new EntityPermissionCollection
{
new EntityPermission(9876, 1234, new string[]{ "A", "F", "C" })
};
var permissionSet = new EntityPermissionSet(1234, permissions);
var userServiceMock = new Mock<IUserService>();
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1,1234,5678")).Returns(permissionSet);
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, 1234, new[] { 'F'});
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, 1234, new[] { 'F'});
//assert
Assert.IsTrue(result);
@@ -151,11 +162,16 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var contentServiceMock = new Mock<IContentService>();
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, null, null, -1);
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, -1);
//assert
Assert.IsTrue(result);
@@ -167,11 +183,16 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var contentServiceMock = new Mock<IContentService>();
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, null, null, -20);
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, -20);
//assert
Assert.IsTrue(result);
@@ -183,11 +204,19 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartContentIds).Returns(new []{ 1234 });
userMock.Setup(u => u.StartContentIds).Returns(new []{ 1234 });
var user = userMock.Object;
var contentServiceMock = new Mock<IContentService>();
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
entityServiceMock.Setup(x => x.GetAll(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<IUmbracoEntity>(entity => entity.Id == 1234 && entity.Path == "-1,1234") });
var entityService = entityServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, null, null, -20);
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, -20);
//assert
Assert.IsFalse(result);
@@ -199,11 +228,19 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartContentIds).Returns(new []{ 1234 });
userMock.Setup(u => u.StartContentIds).Returns(new []{ 1234 });
var user = userMock.Object;
var contentServiceMock = new Mock<IContentService>();
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
entityServiceMock.Setup(x => x.GetAll(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<IUmbracoEntity>(entity => entity.Id == 1234 && entity.Path == "-1,1234") });
var entityService = entityServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, null, null, -1);
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, -1);
//assert
Assert.IsFalse(result);
@@ -215,7 +252,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var userServiceMock = new Mock<IUserService>();
@@ -225,10 +261,15 @@ namespace Umbraco.Tests.Web.Controllers
};
var permissionSet = new EntityPermissionSet(1234, permissions);
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1")).Returns(permissionSet);
var contentServiceMock = new Mock<IContentService>();
var contentService = contentServiceMock.Object;
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, null, -1, new[] { 'A'});
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, -1, new[] { 'A'});
//assert
Assert.IsTrue(result);
@@ -240,7 +281,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var userServiceMock = new Mock<IUserService>();
@@ -251,9 +291,13 @@ namespace Umbraco.Tests.Web.Controllers
var permissionSet = new EntityPermissionSet(1234, permissions);
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-1")).Returns(permissionSet);
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
var contentServiceMock = new Mock<IContentService>();
var contentService = contentServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, null, -1, new[] { 'B'});
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, -1, new[] { 'B'});
//assert
Assert.IsFalse(result);
@@ -265,7 +309,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var userServiceMock = new Mock<IUserService>();
@@ -277,9 +320,13 @@ namespace Umbraco.Tests.Web.Controllers
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-20")).Returns(permissionSet);
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
var contentServiceMock = new Mock<IContentService>();
var contentService = contentServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, null, -20, new[] { 'A'});
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, -20, new[] { 'A'});
//assert
Assert.IsTrue(result);
@@ -291,7 +338,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartContentIds).Returns(new int[0]);
var user = userMock.Object;
var userServiceMock = new Mock<IUserService>();
@@ -302,9 +348,13 @@ namespace Umbraco.Tests.Web.Controllers
var permissionSet = new EntityPermissionSet(1234, permissions);
userServiceMock.Setup(x => x.GetPermissionsForPath(user, "-20")).Returns(permissionSet);
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
var contentServiceMock = new Mock<IContentService>();
var contentService = contentServiceMock.Object;
//act
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, null, -20, new[] { 'B'});
var result = ContentController.CheckPermissions(new Dictionary<string, object>(), user, userService, contentService, entityService, -20, new[] { 'B'});
//assert
Assert.IsFalse(result);
@@ -6,6 +6,8 @@ using System.Net.Http.Headers;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
@@ -19,7 +21,12 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public void GetValueFromResponse_Already_EnumerableContent()
{
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>));
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>), userService, entityService);
var val = new List<ContentItemBasic>() {new ContentItemBasic()};
var result = att.GetValueFromResponse(
new ObjectContent(typeof (IEnumerable<ContentItemBasic>),
@@ -34,7 +41,12 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public void GetValueFromResponse_From_Property()
{
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>), "MyList");
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>), "MyList", userService, entityService);
var val = new List<ContentItemBasic>() { new ContentItemBasic() };
var container = new MyTestClass() {MyList = val};
@@ -51,7 +63,12 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public void GetValueFromResponse_Returns_Null_Not_Found_Property()
{
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>), "DontFind");
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>), "DontFind", userService, entityService);
var val = new List<ContentItemBasic>() { new ContentItemBasic() };
var container = new MyTestClass() { MyList = val };
@@ -68,7 +85,18 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public void Filter_On_Start_Node()
{
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>));
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.StartContentIds).Returns(new[] { 5 });
var user = userMock.Object;
var userServiceMock = new Mock<IUserService>();
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
entityServiceMock.Setup(x => x.GetAll(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<IUmbracoEntity>(entity => entity.Id == 5 && entity.Path == "-1,5") });
var entityService = entityServiceMock.Object;
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>), userService, entityService);
var list = new List<dynamic>();
var path = "";
for (var i = 0; i < 10; i++)
@@ -80,11 +108,6 @@ namespace Umbraco.Tests.Web.Controllers
path += i.ToInvariantString();
list.Add(new ContentItemBasic { Id = i, Name = "Test" + i, ParentId = i, Path = path });
}
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartContentIds).Returns(new []{ 5 });
var user = userMock.Object;
att.FilterBasedOnStartNode(list, user);
@@ -94,8 +117,7 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public void Filter_On_Permissions()
{
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>));
{
var list = new List<dynamic>();
for (var i = 0; i < 10; i++)
{
@@ -119,8 +141,11 @@ namespace Umbraco.Tests.Web.Controllers
};
userServiceMock.Setup(x => x.GetPermissions(user, ids)).Returns(permissions);
var userService = userServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
att.FilterBasedOnPermissions(list, user, userService);
var att = new FilterAllowedOutgoingContentAttribute(typeof(IEnumerable<ContentItemBasic>), userService, entityService);
att.FilterBasedOnPermissions(list, user);
Assert.AreEqual(3, list.Count);
Assert.AreEqual(1, list.ElementAt(0).Id);
@@ -3,6 +3,7 @@ using System.Web.Http;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.Editors;
@@ -18,17 +19,18 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartMediaIds).Returns(new int[0]);
var user = userMock.Object;
var mediaMock = new Mock<IMedia>();
mediaMock.Setup(m => m.Path).Returns("-1,1234,5678");
var media = mediaMock.Object;
var mediaServiceMock = new Mock<IMediaService>();
var mediaServiceMock = new Mock<IMediaService>();
mediaServiceMock.Setup(x => x.GetById(1234)).Returns(media);
var mediaService = mediaServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, 1234);
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, entityService, 1234);
//assert
Assert.IsTrue(result);
@@ -40,7 +42,6 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartMediaIds).Returns(new int[0]);
var user = userMock.Object;
var mediaMock = new Mock<IMedia>();
mediaMock.Setup(m => m.Path).Returns("-1,1234,5678");
@@ -48,9 +49,11 @@ namespace Umbraco.Tests.Web.Controllers
var mediaServiceMock = new Mock<IMediaService>();
mediaServiceMock.Setup(x => x.GetById(0)).Returns(media);
var mediaService = mediaServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act/assert
Assert.Throws<HttpResponseException>(() => MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, 1234));
Assert.Throws<HttpResponseException>(() => MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, entityService, 1234));
}
[Test]
@@ -59,7 +62,7 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(9);
userMock.Setup(u => u.AllStartMediaIds).Returns(new[]{ 9876 });
userMock.Setup(u => u.StartMediaIds).Returns(new[]{ 9876 });
var user = userMock.Object;
var mediaMock = new Mock<IMedia>();
mediaMock.Setup(m => m.Path).Returns("-1,1234,5678");
@@ -67,9 +70,13 @@ namespace Umbraco.Tests.Web.Controllers
var mediaServiceMock = new Mock<IMediaService>();
mediaServiceMock.Setup(x => x.GetById(1234)).Returns(media);
var mediaService = mediaServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
entityServiceMock.Setup(x => x.GetAll(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] {Mock.Of<IUmbracoEntity>(entity => entity.Id == 9876 && entity.Path == "-1,9876")});
var entityService = entityServiceMock.Object;
//act
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, 1234);
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, entityService, 1234);
//assert
Assert.IsFalse(result);
@@ -81,11 +88,14 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartMediaIds).Returns(new int[]{});
var user = userMock.Object;
var mediaServiceMock = new Mock<IMediaService>();
var mediaService = mediaServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, null, -1);
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, entityService, -1);
//assert
Assert.IsTrue(result);
@@ -97,11 +107,17 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartMediaIds).Returns(new[]{ 1234 });
userMock.Setup(u => u.StartMediaIds).Returns(new[]{ 1234 });
var user = userMock.Object;
var mediaServiceMock = new Mock<IMediaService>();
var mediaService = mediaServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
entityServiceMock.Setup(x => x.GetAll(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<IUmbracoEntity>(entity => entity.Id == 1234 && entity.Path == "-1,1234") });
var entityService = entityServiceMock.Object;
//act
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, null, -1);
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, entityService, -1);
//assert
Assert.IsFalse(result);
@@ -113,11 +129,14 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartMediaIds).Returns(new int[]{});
var user = userMock.Object;
var mediaServiceMock = new Mock<IMediaService>();
var mediaService = mediaServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
var entityService = entityServiceMock.Object;
//act
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, null, -21);
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, entityService, -21);
//assert
Assert.IsTrue(result);
@@ -129,11 +148,17 @@ namespace Umbraco.Tests.Web.Controllers
//arrange
var userMock = new Mock<IUser>();
userMock.Setup(u => u.Id).Returns(0);
userMock.Setup(u => u.AllStartMediaIds).Returns(new[]{ 1234 });
userMock.Setup(u => u.StartMediaIds).Returns(new[]{ 1234 });
var user = userMock.Object;
var mediaServiceMock = new Mock<IMediaService>();
var mediaService = mediaServiceMock.Object;
var entityServiceMock = new Mock<IEntityService>();
entityServiceMock.Setup(x => x.GetAll(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<IUmbracoEntity>(entity => entity.Id == 1234 && entity.Path == "-1,1234") });
var entityService = entityServiceMock.Object;
//act
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, null, -21);
var result = MediaController.CheckPermissions(new Dictionary<string, object>(), user, mediaService, entityService, -21);
//assert
Assert.IsFalse(result);
+11 -11
View File
@@ -1023,7 +1023,6 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Performs a permissions check for the user to check if it has access to the node based on
/// start node and/or permissions for the node
@@ -1032,6 +1031,7 @@ namespace Umbraco.Web.Editors
/// <param name="user"></param>
/// <param name="userService"></param>
/// <param name="contentService"></param>
/// <param name="entityService"></param>
/// <param name="nodeId">The content to lookup, if the contentItem is not specified</param>
/// <param name="permissionsToCheck"></param>
/// <param name="contentItem">Specifies the already resolved content item to check against</param>
@@ -1041,10 +1041,16 @@ namespace Umbraco.Web.Editors
IUser user,
IUserService userService,
IContentService contentService,
IEntityService entityService,
int nodeId,
char[] permissionsToCheck = null,
IContent contentItem = null)
{
if (storage == null) throw new ArgumentNullException("storage");
if (user == null) throw new ArgumentNullException("user");
if (userService == null) throw new ArgumentNullException("userService");
if (contentService == null) throw new ArgumentNullException("contentService");
if (entityService == null) throw new ArgumentNullException("entityService");
if (contentItem == null && nodeId != Constants.System.Root && nodeId != Constants.System.RecycleBinContent)
{
@@ -1058,18 +1064,12 @@ namespace Umbraco.Web.Editors
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var hasPathAccess = (nodeId == Constants.System.Root)
? UserExtensions.HasPathAccess(
Constants.System.Root.ToInvariantString(),
user.AllStartContentIds,
Constants.System.RecycleBinContent)
? user.HasContentRootAccess(entityService)
: (nodeId == Constants.System.RecycleBinContent)
? UserExtensions.HasPathAccess(
Constants.System.RecycleBinContent.ToInvariantString(),
user.AllStartContentIds,
Constants.System.RecycleBinContent)
: user.HasPathAccess(contentItem);
? user.HasContentBinAccess(entityService)
: user.HasPathAccess(contentItem, entityService);
if (hasPathAccess == false)
{
@@ -22,18 +22,21 @@ namespace Umbraco.Web.Editors
private readonly IContentService _contentService;
private readonly WebSecurity _security;
private readonly IUserService _userService;
private readonly IEntityService _entityService;
public ContentPostValidateAttribute()
{
}
public ContentPostValidateAttribute(IContentService contentService, IUserService userService, WebSecurity security)
public ContentPostValidateAttribute(IContentService contentService, IUserService userService, IEntityService entityService, WebSecurity security)
{
if (contentService == null) throw new ArgumentNullException("contentService");
if (userService == null) throw new ArgumentNullException("userService");
if (entityService == null) throw new ArgumentNullException("entityService");
if (security == null) throw new ArgumentNullException("security");
_contentService = contentService;
_userService = userService;
_entityService = entityService;
_security = security;
}
@@ -52,6 +55,11 @@ namespace Umbraco.Web.Editors
get { return _userService ?? ApplicationContext.Current.Services.UserService; }
}
private IEntityService EntityService
{
get { return _entityService ?? ApplicationContext.Current.Services.EntityService; }
}
public override bool AllowMultiple
{
get { return true; }
@@ -139,7 +147,8 @@ namespace Umbraco.Web.Editors
actionContext.Request.Properties,
Security.CurrentUser,
UserService,
ContentService,
ContentService,
EntityService,
contentIdToCheck,
permissionToCheck.ToArray(),
contentToCheck) == false)
+6 -6
View File
@@ -551,10 +551,10 @@ namespace Umbraco.Web.Editors
switch (type)
{
case UmbracoEntityTypes.Document:
aids = Security.CurrentUser.AllStartContentIds;
aids = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
break;
case UmbracoEntityTypes.Media:
aids = Security.CurrentUser.AllStartMediaIds;
aids = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
break;
}
@@ -695,14 +695,14 @@ namespace Umbraco.Web.Editors
type = "media";
AddExamineSearchFrom(searchFrom, sb);
AddExamineUserStartNode(Security.CurrentUser.AllStartMediaIds, sb);
AddExamineUserStartNode(Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService), sb);
break;
case UmbracoEntityTypes.Document:
type = "content";
AddExamineSearchFrom(searchFrom, sb);
AddExamineUserStartNode(Security.CurrentUser.AllStartContentIds, sb);
AddExamineUserStartNode(Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService), sb);
break;
default:
@@ -950,10 +950,10 @@ namespace Umbraco.Web.Editors
switch (entityType)
{
case UmbracoEntityTypes.Document:
aids = Security.CurrentUser.AllStartContentIds;
aids = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService);
break;
case UmbracoEntityTypes.Media:
aids = Security.CurrentUser.AllStartMediaIds;
aids = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService);
break;
}
+15 -13
View File
@@ -254,7 +254,7 @@ namespace Umbraco.Web.Editors
private int[] _userStartNodes;
protected int[] UserStartNodes
{
get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.AllStartMediaIds); }
get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService)); }
}
/// <summary>
@@ -680,7 +680,9 @@ namespace Umbraco.Web.Editors
if (CheckPermissions(
new Dictionary<string, object>(),
Security.CurrentUser,
Services.MediaService, parentId) == false)
Services.MediaService,
Services.EntityService,
parentId) == false)
{
return Request.CreateResponse(
HttpStatusCode.Forbidden,
@@ -892,11 +894,17 @@ namespace Umbraco.Web.Editors
/// <param name="storage">The storage to add the content item to so it can be reused</param>
/// <param name="user"></param>
/// <param name="mediaService"></param>
/// <param name="entityService"></param>
/// <param name="nodeId">The content to lookup, if the contentItem is not specified</param>
/// <param name="media">Specifies the already resolved content item to check against, setting this ignores the nodeId</param>
/// <returns></returns>
internal static bool CheckPermissions(IDictionary<string, object> storage, IUser user, IMediaService mediaService, int nodeId, IMedia media = null)
internal static bool CheckPermissions(IDictionary<string, object> storage, IUser user, IMediaService mediaService, IEntityService entityService, int nodeId, IMedia media = null)
{
if (storage == null) throw new ArgumentNullException("storage");
if (user == null) throw new ArgumentNullException("user");
if (mediaService == null) throw new ArgumentNullException("mediaService");
if (entityService == null) throw new ArgumentNullException("entityService");
if (media == null && nodeId != Constants.System.Root && nodeId != Constants.System.RecycleBinMedia)
{
media = mediaService.GetById(nodeId);
@@ -908,19 +916,13 @@ namespace Umbraco.Web.Editors
if (media == null && nodeId != Constants.System.Root && nodeId != Constants.System.RecycleBinMedia)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
var hasPathAccess = (nodeId == Constants.System.Root)
? UserExtensions.HasPathAccess(
Constants.System.Root.ToInvariantString(),
user.AllStartMediaIds,
Constants.System.RecycleBinMedia)
? user.HasMediaRootAccess(entityService)
: (nodeId == Constants.System.RecycleBinMedia)
? UserExtensions.HasPathAccess(
Constants.System.RecycleBinMedia.ToInvariantString(),
user.AllStartMediaIds,
Constants.System.RecycleBinMedia)
: user.HasPathAccess(media);
? user.HasMediaBinAccess(entityService)
: user.HasPathAccess(media, entityService);
return hasPathAccess;
}
@@ -19,17 +19,19 @@ namespace Umbraco.Web.Editors
internal sealed class MediaPostValidateAttribute : ActionFilterAttribute
{
private readonly IMediaService _mediaService;
private readonly IEntityService _entityService;
private readonly WebSecurity _security;
public MediaPostValidateAttribute()
{
}
public MediaPostValidateAttribute(IMediaService mediaService, WebSecurity security)
public MediaPostValidateAttribute(IMediaService mediaService, IEntityService entityService, WebSecurity security)
{
if (mediaService == null) throw new ArgumentNullException("mediaService");
if (security == null) throw new ArgumentNullException("security");
_mediaService = mediaService;
_entityService = entityService;
_security = security;
}
@@ -38,6 +40,11 @@ namespace Umbraco.Web.Editors
get { return _mediaService ?? ApplicationContext.Current.Services.MediaService; }
}
private IEntityService EntityService
{
get { return _entityService ?? ApplicationContext.Current.Services.EntityService; }
}
private WebSecurity Security
{
get { return _security ?? UmbracoContext.Current.Security; }
@@ -81,6 +88,7 @@ namespace Umbraco.Web.Editors
actionContext.Request.Properties,
Security.CurrentUser,
MediaService,
EntityService,
contentIdToCheck,
contentToCheck) == false)
{
@@ -254,7 +254,7 @@ namespace Umbraco.Web.Models.Mapping
var startContentIds = user.StartContentIds.ToArray();
if (startContentIds.Length > 0)
{
{
//TODO: Update GetAll to be able to pass in a parameter like on the normal Get to NOT load in the entire object!
var startNodes = new List<EntityBasic>();
if (startContentIds.Contains(-1))
@@ -276,7 +276,7 @@ namespace Umbraco.Web.Models.Mapping
startNodes.Add(RootNode("Media Root"));
}
var mediaItems = applicationContext.Services.EntityService.GetAll(UmbracoObjectTypes.Media, startMediaIds);
startNodes.AddRange(Mapper.Map<IEnumerable<IUmbracoEntity>, IEnumerable<EntityBasic>>(mediaItems));
startNodes.AddRange(Mapper.Map<IEnumerable<IUmbracoEntity>, IEnumerable<EntityBasic>>(mediaItems));
display.StartMediaIds = startNodes;
}
});
@@ -309,8 +309,8 @@ namespace Umbraco.Web.Models.Mapping
config.CreateMap<IUser, UserDetail>()
.ForMember(detail => detail.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(applicationContext.Services.UserService, applicationContext.ApplicationCache.RuntimeCache)))
.ForMember(detail => detail.UserId, opt => opt.MapFrom(user => GetIntId(user.Id)))
.ForMember(detail => detail.StartContentIds, opt => opt.MapFrom(user => user.AllStartContentIds))
.ForMember(detail => detail.StartMediaIds, opt => opt.MapFrom(user => user.AllStartMediaIds))
.ForMember(detail => detail.StartContentIds, opt => opt.MapFrom(user => user.CalculateContentStartNodeIds(applicationContext.Services.EntityService)))
.ForMember(detail => detail.StartMediaIds, opt => opt.MapFrom(user => user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService)))
.ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
.ForMember(
detail => detail.EmailHash,
@@ -326,8 +326,8 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(detail => detail.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections))
.ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name))
.ForMember(detail => detail.Roles, opt => opt.MapFrom(user => user.Groups.Select(x => x.Alias).ToArray()))
.ForMember(detail => detail.StartContentNodes, opt => opt.MapFrom(user => user.AllStartContentIds))
.ForMember(detail => detail.StartMediaNodes, opt => opt.MapFrom(user => user.AllStartMediaIds))
.ForMember(detail => detail.StartContentNodes, opt => opt.MapFrom(user => user.CalculateContentStartNodeIds(applicationContext.Services.EntityService)))
.ForMember(detail => detail.StartMediaNodes, opt => opt.MapFrom(user => user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService)))
.ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.Username))
.ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
.ForMember(detail => detail.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp));
@@ -65,7 +65,7 @@ namespace Umbraco.Web.Trees
private int[] _userStartNodes;
protected override int[] UserStartNodes
{
get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.AllStartContentIds); }
get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateContentStartNodeIds(Services.EntityService)); }
}
/// <summary>
@@ -215,7 +215,7 @@ namespace Umbraco.Web.Trees
{
return false;
}
return Security.CurrentUser.HasPathAccess(content);
return Security.CurrentUser.HasPathAccess(content, Services.EntityService);
}
/// <summary>
+2 -2
View File
@@ -56,7 +56,7 @@ namespace Umbraco.Web.Trees
private int[] _userStartNodes;
protected override int[] UserStartNodes
{
get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.AllStartMediaIds); }
get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService)); }
}
/// <summary>
@@ -163,7 +163,7 @@ namespace Umbraco.Web.Trees
{
return false;
}
return Security.CurrentUser.HasPathAccess(media);
return Security.CurrentUser.HasPathAccess(media, Services.EntityService);
}
}
}
@@ -102,7 +102,9 @@ namespace Umbraco.Web.WebApi.Filters
actionContext.Request.Properties,
UmbracoContext.Current.Security.CurrentUser,
ApplicationContext.Current.Services.UserService,
ApplicationContext.Current.Services.ContentService, nodeId, _permissionToCheck.HasValue ? new[]{_permissionToCheck.Value}: null))
ApplicationContext.Current.Services.ContentService,
ApplicationContext.Current.Services.EntityService,
nodeId, _permissionToCheck.HasValue ? new[]{_permissionToCheck.Value}: null))
{
base.OnActionExecuting(actionContext);
}
@@ -123,7 +123,9 @@ namespace Umbraco.Web.WebApi.Filters
if (MediaController.CheckPermissions(
actionContext.Request.Properties,
UmbracoContext.Current.Security.CurrentUser,
ApplicationContext.Current.Services.MediaService, nodeId))
ApplicationContext.Current.Services.MediaService,
ApplicationContext.Current.Services.EntityService,
nodeId))
{
base.OnActionExecuting(actionContext);
}
@@ -18,36 +18,70 @@ namespace Umbraco.Web.WebApi.Filters
/// </summary>
internal sealed class FilterAllowedOutgoingContentAttribute : FilterAllowedOutgoingMediaAttribute
{
private readonly IUserService _userService;
private readonly IEntityService _entityService;
private readonly char _permissionToCheck;
public FilterAllowedOutgoingContentAttribute(Type outgoingType)
: base(outgoingType)
: this(outgoingType, ApplicationContext.Current.Services.UserService, ApplicationContext.Current.Services.EntityService)
{
_permissionToCheck = ActionBrowse.Instance.Letter;
}
public FilterAllowedOutgoingContentAttribute(Type outgoingType, char permissionToCheck)
: base(outgoingType)
: this(outgoingType, ApplicationContext.Current.Services.UserService, ApplicationContext.Current.Services.EntityService)
{
_permissionToCheck = permissionToCheck;
}
public FilterAllowedOutgoingContentAttribute(Type outgoingType, string propertyName)
: base(outgoingType, propertyName)
: this(outgoingType, propertyName, ApplicationContext.Current.Services.UserService, ApplicationContext.Current.Services.EntityService)
{
_permissionToCheck = ActionBrowse.Instance.Letter;
}
public FilterAllowedOutgoingContentAttribute(Type outgoingType, IUserService userService, IEntityService entityService)
: base(outgoingType)
{
if (userService == null) throw new ArgumentNullException("userService");
if (entityService == null) throw new ArgumentNullException("entityService");
_userService = userService;
_entityService = entityService;
_permissionToCheck = ActionBrowse.Instance.Letter;
}
public FilterAllowedOutgoingContentAttribute(Type outgoingType, char permissionToCheck, IUserService userService, IEntityService entityService)
: base(outgoingType)
{
if (userService == null) throw new ArgumentNullException("userService");
if (entityService == null) throw new ArgumentNullException("entityService");
_userService = userService;
_entityService = entityService;
_permissionToCheck = permissionToCheck;
}
public FilterAllowedOutgoingContentAttribute(Type outgoingType, string propertyName, IUserService userService, IEntityService entityService)
: base(outgoingType, propertyName)
{
if (userService == null) throw new ArgumentNullException("userService");
if (entityService == null) throw new ArgumentNullException("entityService");
_userService = userService;
_entityService = entityService;
_permissionToCheck = ActionBrowse.Instance.Letter;
}
protected override void FilterItems(IUser user, IList items)
{
base.FilterItems(user, items);
FilterBasedOnPermissions(items, user, ApplicationContext.Current.Services.UserService);
FilterBasedOnPermissions(items, user);
}
protected override int[] GetUserStartNodes(IUser user)
{
return user.AllStartContentIds;
return user.CalculateContentStartNodeIds(_entityService);
}
protected override int RecycleBinId
@@ -55,7 +89,7 @@ namespace Umbraco.Web.WebApi.Filters
get { return Constants.System.RecycleBinContent; }
}
internal void FilterBasedOnPermissions(IList items, IUser user, IUserService userService)
internal void FilterBasedOnPermissions(IList items, IUser user)
{
var length = items.Count;
@@ -67,7 +101,7 @@ namespace Umbraco.Web.WebApi.Filters
ids.Add(((dynamic)items[i]).Id);
}
//get all the permissions for these nodes in one call
var permissions = userService.GetPermissions(user, ids.ToArray()).ToArray();
var permissions = _userService.GetPermissions(user, ids.ToArray()).ToArray();
var toRemove = new List<dynamic>();
foreach (dynamic item in items)
{
@@ -41,7 +41,7 @@ namespace Umbraco.Web.WebApi.Filters
protected virtual int[] GetUserStartNodes(IUser user)
{
return user.AllStartMediaIds;
return user.CalculateMediaStartNodeIds(ApplicationContext.Current.Services.EntityService);
}
protected virtual int RecycleBinId
+15 -15
View File
@@ -23,7 +23,7 @@ namespace umbraco.BasePages
{
/// <summary>
/// umbraco.BasePages.BasePage is the default page type for the umbraco backend.
/// The basepage keeps track of the current user and the page context. But does not
/// The basepage keeps track of the current user and the page context. But does not
/// Restrict access to the page itself.
/// The keep the page secure, the umbracoEnsuredPage class should be used instead
/// </summary>
@@ -33,7 +33,7 @@ namespace umbraco.BasePages
private User _user;
private bool _userisValidated = false;
private ClientTools _clientTools;
/// <summary>
/// The path to the umbraco root folder
/// </summary>
@@ -56,7 +56,7 @@ namespace umbraco.BasePages
protected static ISqlHelper SqlHelper
{
get { return BusinessLogic.Application.SqlHelper; }
}
}
/// <summary>
/// Returns the current ApplicationContext
@@ -83,7 +83,7 @@ namespace umbraco.BasePages
}
/// <summary>
/// Returns the current BasePage for the current request.
/// Returns the current BasePage for the current request.
/// This assumes that the current page is a BasePage, otherwise, returns null;
/// </summary>
[Obsolete("Should use the Umbraco.Web.UmbracoContext.Current singleton instead to access common methods and properties")]
@@ -93,9 +93,9 @@ namespace umbraco.BasePages
{
var page = HttpContext.Current.CurrentHandler as BasePage;
if (page != null) return page;
//the current handler is not BasePage but people might be expecting this to be the case if they
//the current handler is not BasePage but people might be expecting this to be the case if they
// are using this singleton accesor... which is legacy code now and shouldn't be used. When people
// start using Umbraco.Web.UI.Pages.BasePage then this will not be the case! So, we'll just return a
// start using Umbraco.Web.UI.Pages.BasePage then this will not be the case! So, we'll just return a
// new instance of BasePage as a hack to make it work.
if (HttpContext.Current.Items["umbraco.BasePages.BasePage"] == null)
{
@@ -186,7 +186,7 @@ namespace umbraco.BasePages
var identity = HttpContext.Current.GetCurrentIdentity(
//DO NOT AUTO-AUTH UNLESS THE CURRENT HANDLER IS WEBFORMS!
// Without this check, anything that is using this legacy API, like ui.Text will
// automatically log the back office user in even if it is a front-end request (if there is
// automatically log the back office user in even if it is a front-end request (if there is
// a back office user logged in. This can cause problems becaues the identity is changing mid
// request. For example: http://issues.umbraco.org/issue/U4-4010
HttpContext.Current.CurrentHandler is Page);
@@ -217,7 +217,7 @@ namespace umbraco.BasePages
var identity = HttpContext.Current.GetCurrentIdentity(
//DO NOT AUTO-AUTH UNLESS THE CURRENT HANDLER IS WEBFORMS!
// Without this check, anything that is using this legacy API, like ui.Text will
// automatically log the back office user in even if it is a front-end request (if there is
// automatically log the back office user in even if it is a front-end request (if there is
// a back office user logged in. This can cause problems becaues the identity is changing mid
// request. For example: http://issues.umbraco.org/issue/U4-4010
HttpContext.Current.CurrentHandler is Page);
@@ -234,7 +234,7 @@ namespace umbraco.BasePages
{
var ticket = HttpContext.Current.GetUmbracoAuthTicket();
if (ticket.Expired) return 0;
var ticks = ticket.Expiration.Ticks - DateTime.Now.Ticks;
var ticks = ticket.Expiration.Ticks - DateTime.Now.Ticks;
return ticks;
}
@@ -251,7 +251,7 @@ namespace umbraco.BasePages
var identity = HttpContext.Current.GetCurrentIdentity(
//DO NOT AUTO-AUTH UNLESS THE CURRENT HANDLER IS WEBFORMS!
// Without this check, anything that is using this legacy API, like ui.Text will
// automatically log the back office user in even if it is a front-end request (if there is
// automatically log the back office user in even if it is a front-end request (if there is
// a back office user logged in. This can cause problems becaues the identity is changing mid
// request. For example: http://issues.umbraco.org/issue/U4-4010
HttpContext.Current.CurrentHandler is Page);
@@ -279,7 +279,7 @@ namespace umbraco.BasePages
public static void RenewLoginTimeout()
{
HttpContext.Current.RenewUmbracoAuthTicket();
HttpContext.Current.RenewUmbracoAuthTicket();
}
/// <summary>
@@ -294,8 +294,8 @@ namespace umbraco.BasePages
AllowedApplications = u.GetApplications().Select(x => x.alias).ToArray(),
RealName = u.Name,
Roles = u.GetGroups(),
StartContentNodes = u.UserEntity.AllStartContentIds,
StartMediaNodes = u.UserEntity.AllStartMediaIds,
StartContentNodes = u.UserEntity.CalculateContentStartNodeIds(ApplicationContext.Current.Services.EntityService),
StartMediaNodes = u.UserEntity.CalculateMediaStartNodeIds(ApplicationContext.Current.Services.EntityService),
Username = u.LoginName,
Culture = ui.Culture(u)
@@ -342,7 +342,7 @@ namespace umbraco.BasePages
}
//[Obsolete("Use ClientTools instead")]
//public void reloadParentNode()
//public void reloadParentNode()
//{
// ClientTools.ReloadParentNode(true);
//}
@@ -379,7 +379,7 @@ namespace umbraco.BasePages
{
base.OnInit(e);
//This must be set on each page to mitigate CSRF attacks which ensures that this unique token
//This must be set on each page to mitigate CSRF attacks which ensures that this unique token
// is added to the viewstate of each request
if (umbracoUserContextID.IsNullOrWhiteSpace() == false)
{