Files
Umbraco-CMS/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Security/ContentPermissionsTests.cs
Bjarke Berg 2494d8c5aa Granular permissions in Management API (#15734)
* It builds..

* Added granular permissions

* Added granular permissions

* Rename content to document

* Added migration

* Fixed issues causing the migration from v13 was not possible.

* Merged Permissions and Granular Permissions in viewmodel

* Prepared the viewmodel to a future where permissions can be more types.

* OpenApi

* Allow to translate a single char to many strings

* Use frontend friendly values for known permissions

* Validate the documents exist

* Allow setting non-document settings

* Add "$type" when required

* Rename to presentation model and update OpenApi.json

* OpenApi.json

* Fix tests

* OpenAPI

* Fixed issues with upgrades

* Add the discriminator name

* Fixed issues that only happended on SqlServer

* Fixed queries for SqlServer

* Clean up

* More cleanup

* Fix issue when migrating sqlserver

* Split fallback permissions into own concept in view model

* Also split on current user

* Added a extenable pattern for mappers between DTO => Granular Permission => ViewModel and ViewModel => Granular Permission

* Fixed issue with new exists method, that did not take duplicate keys into account.

* Added sections to current user response model

* Formatting fixes

* Move class to its own file

* xml comment

---------

Co-authored-by: Zeegaan <skrivdetud@gmail.com>
2024-02-27 21:57:02 +01:00

354 lines
15 KiB
C#

// Copyright (c) Umbraco.
// See LICENSE for more details.
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Entities;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Security;
[TestFixture]
public class ContentPermissionsTests
{
[Test]
public void Access_Allowed_By_Path()
{
// Arrange
var user = CreateUser(9);
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
var content = contentMock.Object;
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(1234, user, out IContent _);
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result);
}
[Test]
public void No_Content_Found()
{
// Arrange
var user = CreateUser(9);
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
var content = contentMock.Object;
var contentServiceMock = new Mock<IContentService>();
contentServiceMock.Setup(x => x.GetById(0)).Returns(content);
var contentService = contentServiceMock.Object;
var userServiceMock = new Mock<IUserService>();
var permissions = new EntityPermissionCollection();
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(1234, user, out IContent _, new[] { "F" }.ToHashSet());
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.NotFound, result);
}
[Test]
public void No_Access_By_Path()
{
// Arrange
var user = CreateUser(9, 9876);
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
var content = contentMock.Object;
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();
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.GetAllPaths(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<TreeEntityPath>(entity => entity.Id == 9876 && entity.Path == "-1,9876") });
var entityService = entityServiceMock.Object;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(1234, user, out IContent _, new[] { "F" }.ToHashSet());
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result);
}
[Test]
public void No_Access_By_Permission()
{
// Arrange
var user = CreateUser(9);
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
var content = contentMock.Object;
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(9876, 1234, new[] { "A", "B", "C" }.ToHashSet()) };
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(1234, user, out IContent _, new[] { "F" }.ToHashSet());
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result);
}
[Test]
public void Access_Allowed_By_Permission()
{
// Arrange
var user = CreateUser(9);
var contentMock = new Mock<IContent>();
contentMock.Setup(c => c.Path).Returns("-1,1234,5678");
var content = contentMock.Object;
var contentServiceMock = new Mock<IContentService>();
contentServiceMock.Setup(x => x.GetById(1234)).Returns(content);
var contentService = contentServiceMock.Object;
var permissions = new EntityPermissionCollection { new(9876, 1234, new[] { "A", "F", "C" }.ToHashSet()) };
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(1234, user, out IContent _, new[] { "F" }.ToHashSet());
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result);
}
[Test]
public void Access_To_Root_By_Path()
{
// Arrange
var user = CreateUser();
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(-1, user, out IContent _);
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result);
}
[Test]
public void Access_To_Recycle_Bin_By_Path()
{
// Arrange
var user = CreateUser();
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(-20, user, out IContent _);
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result);
}
[Test]
public void No_Access_To_Recycle_Bin_By_Path()
{
// Arrange
var user = CreateUser(startContentId: 1234);
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.GetAllPaths(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<TreeEntityPath>(entity => entity.Id == 1234 && entity.Path == "-1,1234") });
var entityService = entityServiceMock.Object;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(-20, user, out IContent _);
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result);
}
[Test]
public void No_Access_To_Root_By_Path()
{
// Arrange
var user = CreateUser(startContentId: 1234);
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.GetAllPaths(It.IsAny<UmbracoObjectTypes>(), It.IsAny<int[]>()))
.Returns(new[] { Mock.Of<TreeEntityPath>(entity => entity.Id == 1234 && entity.Path == "-1,1234") });
var entityService = entityServiceMock.Object;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(-1, user, out IContent _);
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result);
}
[Test]
public void Access_To_Root_By_Permission()
{
// Arrange
var user = CreateUser();
var userServiceMock = new Mock<IUserService>();
var permissions = new EntityPermissionCollection { new(9876, 1234, new[] { "A" }.ToHashSet()) };
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(-1, user, out IContent _, new[] { "A" }.ToHashSet());
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result);
}
[Test]
public void No_Access_To_Root_By_Permission()
{
// Arrange
var user = CreateUser(withUserGroup: false);
var userServiceMock = new Mock<IUserService>();
var permissions = new EntityPermissionCollection { new(9876, 1234, new[] { "A" }.ToHashSet()) };
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(-1, user, out IContent _, new[] { "B" }.ToHashSet());
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result);
}
[Test]
public void Access_To_Recycle_Bin_By_Permission()
{
// Arrange
var user = CreateUser();
var userServiceMock = new Mock<IUserService>();
var permissions = new EntityPermissionCollection { new(9876, 1234, new[] { "A" }.ToHashSet()) };
var permissionSet = new EntityPermissionSet(-20, 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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(-20, user, out IContent _, new[] { "A" }.ToHashSet());
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Granted, result);
}
[Test]
public void No_Access_To_Recycle_Bin_By_Permission()
{
// Arrange
var user = CreateUser(withUserGroup: false);
var userServiceMock = new Mock<IUserService>();
var permissions = new EntityPermissionCollection { new(9876, 1234, new[] { "A" }.ToHashSet()) };
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;
var contentPermissions = new ContentPermissions(userService, contentService, entityService, AppCaches.Disabled);
// Act
var result = contentPermissions.CheckPermissions(-20, user, out IContent _, new[] { "B" }.ToHashSet());
// Assert
Assert.AreEqual(ContentPermissions.ContentAccess.Denied, result);
}
private IUser CreateUser(int id = 0, int? startContentId = null, bool withUserGroup = true)
{
var builder = new UserBuilder()
.WithId(id)
.WithStartContentIds(startContentId.HasValue ? new[] { startContentId.Value } : new int[0]);
if (withUserGroup)
{
builder = builder
.AddUserGroup()
.WithId(1)
.WithName("admin")
.WithAlias("admin")
.Done();
}
return builder.Build();
}
}